From 3d36f1974e1af7d951fd5f0de4fe8b5659759f5f Mon Sep 17 00:00:00 2001 From: Patrick Tschuchnig Date: Mon, 22 Oct 2018 11:59:30 +0200 Subject: [PATCH] =?UTF-8?q?First=20Commit,=20=C3=9Cbertragung=20von=20exte?= =?UTF-8?q?rnem=20Server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 0 .idea/codeStyles/Project.xml | 0 .idea/gradle.xml | 0 .idea/misc.xml | 0 .idea/runConfigurations.xml | 0 .idea/vcs.xml | 0 README.md | 0 app/.gitignore | 0 app/build.gradle | 0 app/proguard-rules.pro | 0 .../user/myapp/ExampleInstrumentedTest.java | 26 - app/src/main/AndroidManifest.xml | 0 .../user/myapp/DisplayMessageActivity.java | 188 ------ .../com/example/user/myapp/GlobalState.java | 77 --- .../com/example/user/myapp/MainActivity.java | 268 --------- .../user/myapp/ManualDriveActivity.java | 382 ------------ .../user/myapp/MeasurementActivity.java | 20 - .../example/user/myapp/MyIntentService.java | 204 ------- .../user/myapp/OnSwipeTouchListener.java | 113 ---- .../java/com/ghgande/j2mod/modbus/Modbus.java | 349 ----------- .../ghgande/j2mod/modbus/ModbusException.java | 74 --- .../j2mod/modbus/ModbusIOException.java | 119 ---- .../j2mod/modbus/ModbusSlaveException.java | 125 ---- .../modbus/facade/AbstractModbusMaster.java | 495 ---------------- .../j2mod/modbus/facade/ModbusTCPMaster.java | 190 ------ .../j2mod/modbus/facade/ModbusUDPMaster.java | 121 ---- .../modbus/io/AbstractModbusTransport.java | 118 ---- .../io/AbstractSerialTransportListener.java | 83 --- .../j2mod/modbus/io/BytesInputStream.java | 184 ------ .../j2mod/modbus/io/BytesOutputStream.java | 119 ---- .../modbus/io/FastByteArrayInputStream.java | 166 ------ .../modbus/io/FastByteArrayOutputStream.java | 268 --------- .../modbus/io/ModbusRTUTCPTransport.java | 63 -- .../j2mod/modbus/io/ModbusTCPTransaction.java | 247 -------- .../j2mod/modbus/io/ModbusTCPTransport.java | 407 ------------- .../j2mod/modbus/io/ModbusTransaction.java | 171 ------ .../j2mod/modbus/io/ModbusUDPTransaction.java | 185 ------ .../j2mod/modbus/io/ModbusUDPTransport.java | 152 ----- .../j2mod/modbus/io/NonWordDataHandler.java | 93 --- .../j2mod/modbus/msg/ExceptionResponse.java | 112 ---- .../msg/IllegalAddressExceptionResponse.java | 45 -- .../msg/IllegalFunctionExceptionResponse.java | 45 -- .../modbus/msg/IllegalFunctionRequest.java | 103 ---- .../msg/IllegalValueExceptionResponse.java | 45 -- .../modbus/msg/MaskWriteRegisterRequest.java | 195 ------ .../modbus/msg/MaskWriteRegisterResponse.java | 136 ----- .../j2mod/modbus/msg/ModbusMessage.java | 154 ----- .../j2mod/modbus/msg/ModbusMessageImpl.java | 220 ------- .../j2mod/modbus/msg/ModbusRequest.java | 189 ------ .../j2mod/modbus/msg/ModbusResponse.java | 162 ----- .../j2mod/modbus/msg/ReadCoilsRequest.java | 176 ------ .../j2mod/modbus/msg/ReadCoilsResponse.java | 167 ------ .../msg/ReadCommEventCounterRequest.java | 81 --- .../msg/ReadCommEventCounterResponse.java | 117 ---- .../modbus/msg/ReadCommEventLogRequest.java | 81 --- .../modbus/msg/ReadCommEventLogResponse.java | 202 ------- .../msg/ReadExceptionStatusRequest.java | 81 --- .../msg/ReadExceptionStatusResponse.java | 92 --- .../modbus/msg/ReadFIFOQueueRequest.java | 129 ---- .../modbus/msg/ReadFIFOQueueResponse.java | 161 ----- .../modbus/msg/ReadFileRecordRequest.java | 264 --------- .../modbus/msg/ReadFileRecordResponse.java | 219 ------- .../modbus/msg/ReadInputDiscretesRequest.java | 177 ------ .../msg/ReadInputDiscretesResponse.java | 165 ------ .../modbus/msg/ReadInputRegistersRequest.java | 163 ----- .../msg/ReadInputRegistersResponse.java | 183 ------ .../j2mod/modbus/msg/ReadMEIRequest.java | 178 ------ .../j2mod/modbus/msg/ReadMEIResponse.java | 205 ------- .../msg/ReadMultipleRegistersRequest.java | 163 ----- .../msg/ReadMultipleRegistersResponse.java | 184 ------ .../msg/ReadSerialDiagnosticsRequest.java | 168 ------ .../msg/ReadSerialDiagnosticsResponse.java | 154 ----- .../modbus/msg/ReadWriteMultipleRequest.java | 372 ------------ .../modbus/msg/ReadWriteMultipleResponse.java | 198 ------- .../modbus/msg/ReportSlaveIDRequest.java | 81 --- .../modbus/msg/ReportSlaveIDResponse.java | 178 ------ .../j2mod/modbus/msg/WriteCoilRequest.java | 178 ------ .../j2mod/modbus/msg/WriteCoilResponse.java | 132 ----- .../modbus/msg/WriteFileRecordRequest.java | 304 ---------- .../modbus/msg/WriteFileRecordResponse.java | 235 -------- .../modbus/msg/WriteMultipleCoilsRequest.java | 261 -------- .../msg/WriteMultipleCoilsResponse.java | 135 ----- .../msg/WriteMultipleRegistersRequest.java | 322 ---------- .../msg/WriteMultipleRegistersResponse.java | 138 ----- .../msg/WriteSingleRegisterRequest.java | 156 ----- .../msg/WriteSingleRegisterResponse.java | 133 ----- .../modbus/net/AbstractModbusListener.java | 196 ------ .../modbus/net/AbstractSerialConnection.java | 190 ------ .../j2mod/modbus/net/AbstractUDPTerminal.java | 123 ---- .../j2mod/modbus/net/ModbusTCPListener.java | 189 ------ .../j2mod/modbus/net/ModbusUDPListener.java | 124 ---- .../modbus/net/TCPConnectionHandler.java | 71 --- .../j2mod/modbus/net/TCPMasterConnection.java | 338 ----------- .../j2mod/modbus/net/TCPSlaveConnection.java | 180 ------ .../j2mod/modbus/net/UDPMasterConnection.java | 174 ------ .../j2mod/modbus/net/UDPMasterTerminal.java | 104 ---- .../j2mod/modbus/net/UDPSlaveTerminal.java | 250 -------- .../modbus/procimg/AbstractRegister.java | 70 --- .../procimg/DefaultProcessImageFactory.java | 140 ----- .../j2mod/modbus/procimg/DigitalIn.java | 39 -- .../j2mod/modbus/procimg/DigitalOut.java | 49 -- .../ghgande/j2mod/modbus/procimg/FIFO.java | 83 --- .../ghgande/j2mod/modbus/procimg/File.java | 68 --- .../procimg/IllegalAddressException.java | 50 -- .../j2mod/modbus/procimg/InputRegister.java | 60 -- .../modbus/procimg/ObservableDigitalOut.java | 51 -- .../modbus/procimg/ObservableRegister.java | 69 --- .../j2mod/modbus/procimg/ProcessImage.java | 228 ------- .../modbus/procimg/ProcessImageFactory.java | 104 ---- .../procimg/ProcessImageImplementation.java | 239 -------- .../ghgande/j2mod/modbus/procimg/Record.java | 72 --- .../j2mod/modbus/procimg/Register.java | 53 -- .../j2mod/modbus/procimg/SimpleDigitalIn.java | 66 --- .../modbus/procimg/SimpleDigitalOut.java | 60 -- .../modbus/procimg/SimpleInputRegister.java | 66 --- .../modbus/procimg/SimpleProcessImage.java | 551 ----------------- .../j2mod/modbus/procimg/SimpleRegister.java | 70 --- .../procimg/SynchronizedAbstractRegister.java | 97 --- .../j2mod/modbus/slave/ModbusSlave.java | 272 --------- .../modbus/slave/ModbusSlaveFactory.java | 219 ------- .../j2mod/modbus/slave/ModbusSlaveType.java | 52 -- .../ghgande/j2mod/modbus/util/BitVector.java | 359 ----------- .../ghgande/j2mod/modbus/util/ModbusUtil.java | 534 ----------------- .../ghgande/j2mod/modbus/util/Observable.java | 88 --- .../ghgande/j2mod/modbus/util/Observer.java | 39 -- .../j2mod/modbus/util/SerialParameters.java | 557 ------------------ .../ghgande/j2mod/modbus/util/ThreadPool.java | 126 ---- .../drawable-v24/ic_launcher_foreground.xml | 0 app/src/main/res/drawable/con1.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 app/src/main/res/drawable/ls1.xml | 0 app/src/main/res/drawable/zyl1.xml | 0 app/src/main/res/drawable/zyl2.xml | 0 .../res/layout/activity_display_message.xml | 0 app/src/main/res/layout/activity_main.xml | 0 .../main/res/layout/activity_manual_drive.xml | 0 .../main/res/layout/activity_measurement.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin app/src/main/res/values/colors.xml | 0 app/src/main/res/values/strings.xml | 0 app/src/main/res/values/styles.xml | 0 .../example/user/myapp/ExampleUnitTest.java | 17 - build.gradle | 0 documentation/Tag Liste.xlsx | Bin documentation/doku.ods | Bin gradle.properties | 0 gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew | 0 gradlew.bat | 0 plc-program/Schauanlage-Elektropneumatik.mnp | Bin 35732 -> 0 bytes .../V4/Schauanlage-Elektropneumatik.mnp | Bin 0 -> 35948 bytes plc-program/V4/notizen | 2 + .../V5/Schauanlage-Elektropneumatik_V5.mnp | Bin 0 -> 35991 bytes plc-program/network-inputs-udf.lma | 0 settings.gradle | 0 167 files changed, 2 insertions(+), 19233 deletions(-) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .idea/codeStyles/Project.xml mode change 100644 => 100755 .idea/gradle.xml mode change 100644 => 100755 .idea/misc.xml mode change 100644 => 100755 .idea/runConfigurations.xml mode change 100644 => 100755 .idea/vcs.xml mode change 100644 => 100755 README.md mode change 100644 => 100755 app/.gitignore mode change 100644 => 100755 app/build.gradle mode change 100644 => 100755 app/proguard-rules.pro delete mode 100644 app/src/androidTest/java/com/example/user/myapp/ExampleInstrumentedTest.java mode change 100644 => 100755 app/src/main/AndroidManifest.xml delete mode 100644 app/src/main/java/com/example/user/myapp/DisplayMessageActivity.java delete mode 100644 app/src/main/java/com/example/user/myapp/GlobalState.java delete mode 100644 app/src/main/java/com/example/user/myapp/MainActivity.java delete mode 100644 app/src/main/java/com/example/user/myapp/ManualDriveActivity.java delete mode 100644 app/src/main/java/com/example/user/myapp/MeasurementActivity.java delete mode 100644 app/src/main/java/com/example/user/myapp/MyIntentService.java delete mode 100644 app/src/main/java/com/example/user/myapp/OnSwipeTouchListener.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/Modbus.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/ModbusException.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/ModbusIOException.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/ModbusSlaveException.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/facade/AbstractModbusMaster.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusUDPMaster.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractModbusTransport.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractSerialTransportListener.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/BytesInputStream.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/BytesOutputStream.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayInputStream.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayOutputStream.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusRTUTCPTransport.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransaction.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransport.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTransaction.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransaction.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransport.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/io/NonWordDataHandler.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ExceptionResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalAddressExceptionResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionExceptionResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalValueExceptionResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessage.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessageImpl.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterRequest.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterResponse.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractModbusListener.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractSerialConnection.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractUDPTerminal.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusTCPListener.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusUDPListener.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/TCPConnectionHandler.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/TCPSlaveConnection.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterConnection.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterTerminal.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/net/UDPSlaveTerminal.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/AbstractRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/DefaultProcessImageFactory.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalIn.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalOut.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/FIFO.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/File.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/IllegalAddressException.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/InputRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableDigitalOut.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImage.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageFactory.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageImplementation.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/Record.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/Register.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalIn.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalOut.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleInputRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleProcessImage.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/procimg/SynchronizedAbstractRegister.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlave.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveFactory.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveType.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/BitVector.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/ModbusUtil.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/Observable.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/Observer.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/SerialParameters.java delete mode 100644 app/src/main/java/com/ghgande/j2mod/modbus/util/ThreadPool.java mode change 100644 => 100755 app/src/main/res/drawable-v24/ic_launcher_foreground.xml mode change 100644 => 100755 app/src/main/res/drawable/con1.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_launcher_background.xml mode change 100644 => 100755 app/src/main/res/drawable/ls1.xml mode change 100644 => 100755 app/src/main/res/drawable/zyl1.xml mode change 100644 => 100755 app/src/main/res/drawable/zyl2.xml mode change 100644 => 100755 app/src/main/res/layout/activity_display_message.xml mode change 100644 => 100755 app/src/main/res/layout/activity_main.xml mode change 100644 => 100755 app/src/main/res/layout/activity_manual_drive.xml mode change 100644 => 100755 app/src/main/res/layout/activity_measurement.xml mode change 100644 => 100755 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml mode change 100644 => 100755 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml mode change 100644 => 100755 app/src/main/res/mipmap-hdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-hdpi/ic_launcher_round.png mode change 100644 => 100755 app/src/main/res/mipmap-mdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-mdpi/ic_launcher_round.png mode change 100644 => 100755 app/src/main/res/mipmap-xhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png mode change 100644 => 100755 app/src/main/res/mipmap-xxhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png mode change 100644 => 100755 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png mode change 100644 => 100755 app/src/main/res/values/colors.xml mode change 100644 => 100755 app/src/main/res/values/strings.xml mode change 100644 => 100755 app/src/main/res/values/styles.xml delete mode 100644 app/src/test/java/com/example/user/myapp/ExampleUnitTest.java mode change 100644 => 100755 build.gradle mode change 100644 => 100755 documentation/Tag Liste.xlsx mode change 100644 => 100755 documentation/doku.ods mode change 100644 => 100755 gradle.properties mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.jar mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat delete mode 100644 plc-program/Schauanlage-Elektropneumatik.mnp create mode 100755 plc-program/V4/Schauanlage-Elektropneumatik.mnp create mode 100755 plc-program/V4/notizen create mode 100755 plc-program/V5/Schauanlage-Elektropneumatik_V5.mnp mode change 100644 => 100755 plc-program/network-inputs-udf.lma mode change 100644 => 100755 settings.gradle diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml old mode 100644 new mode 100755 diff --git a/.idea/gradle.xml b/.idea/gradle.xml old mode 100644 new mode 100755 diff --git a/.idea/misc.xml b/.idea/misc.xml old mode 100644 new mode 100755 diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml old mode 100644 new mode 100755 diff --git a/.idea/vcs.xml b/.idea/vcs.xml old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/app/.gitignore b/app/.gitignore old mode 100644 new mode 100755 diff --git a/app/build.gradle b/app/build.gradle old mode 100644 new mode 100755 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro old mode 100644 new mode 100755 diff --git a/app/src/androidTest/java/com/example/user/myapp/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/user/myapp/ExampleInstrumentedTest.java deleted file mode 100644 index b8d289f..0000000 --- a/app/src/androidTest/java/com/example/user/myapp/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.example.user.myapp; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.example.user.myapp", appContext.getPackageName()); - } -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml old mode 100644 new mode 100755 diff --git a/app/src/main/java/com/example/user/myapp/DisplayMessageActivity.java b/app/src/main/java/com/example/user/myapp/DisplayMessageActivity.java deleted file mode 100644 index 3717a74..0000000 --- a/app/src/main/java/com/example/user/myapp/DisplayMessageActivity.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.example.user.myapp; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.ArrayList; - -public class DisplayMessageActivity extends AppCompatActivity { - - private Handler handlerCoil; - private Handler handlerInputRegister; - private Handler handlerDiscreteInput; - - private GlobalState state; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_display_message); - - // listener - LocalBroadcastManager.getInstance(this).registerReceiver(coilMessageReceiver, new IntentFilter("readOnlyCoil")); - LocalBroadcastManager.getInstance(this).registerReceiver(discreteInputMessageReceiver, new IntentFilter("readOnlyDiscreteInput")); - LocalBroadcastManager.getInstance(this).registerReceiver(inputRegisterMessageReceiver, new IntentFilter("readOnlyInputRegister")); - - state = (GlobalState) getApplicationContext(); - - Toast toast = Toast.makeText(getApplicationContext(), "This is my toast !", Toast.LENGTH_LONG); - toast.show(); - //handler - handlerCoil = new Handler(); - handlerCoil.post(refreshCoil); - - handlerInputRegister = new Handler(); - handlerInputRegister.post(refreshInputRegister); - - handlerDiscreteInput = new Handler(); - handlerDiscreteInput.post(refreshDiscreteInput); - } - - Runnable refreshCoil = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.Q_COIL.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.Q_COIL.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyCoil"); - getApplicationContext().startService(serviceIntent); - - handlerCoil.postDelayed(this, 2000); - } - }; - - Runnable refreshDiscreteInput = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.discrete.input"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.I_DI.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.I_DI.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyDiscreteInput"); - getApplicationContext().startService(serviceIntent); - - handlerDiscreteInput.postDelayed(this, 5000); - } - }; - - Runnable refreshInputRegister = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.input.register"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.AI_IR.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.AI_IR.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyInputRegister"); - getApplicationContext().startService(serviceIntent); - - handlerInputRegister.postDelayed(this, 1000); - } - }; - - // on message receive, update the view with values - private BroadcastReceiver coilMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - Bundle bundle = intent.getExtras(); - boolean[] booleanArray = bundle.getBooleanArray("coilValues"); - - TextView textView1 = findViewById(R.id.textView1); - textView1.setText(new Boolean(booleanArray[0]).toString()); - - TextView textView2 = findViewById(R.id.textView2); - textView2.setText(new Boolean(booleanArray[1]).toString()); - - TextView textView3 = findViewById(R.id.textView3); - textView3.setText(new Boolean(booleanArray[2]).toString()); - - TextView textView4 = findViewById(R.id.textView4); - textView4.setText(new Boolean(booleanArray[3]).toString()); - - TextView textView5 = findViewById(R.id.textView5); - textView5.setText(new Boolean(booleanArray[4]).toString()); - - TextView textView6 = findViewById(R.id.textView6); - textView6.setText(new Boolean(booleanArray[5]).toString()); - - TextView textView7 = findViewById(R.id.textView7); - textView7.setText(new Boolean(booleanArray[6]).toString()); - - TextView textView8 = findViewById(R.id.textView8); - textView8.setText(new Boolean(booleanArray[7]).toString()); - } - }; - - private BroadcastReceiver inputRegisterMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - Bundle bundle = intent.getExtras(); - ArrayList integerArrayList = bundle.getIntegerArrayList("irValues"); - - TextView textView9 = findViewById(R.id.textView9); - textView9.setText(integerArrayList.get(0).toString()); - } - }; - - private BroadcastReceiver discreteInputMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - Bundle bundle = intent.getExtras(); - boolean[] booleanArray = bundle.getBooleanArray("discreteInputValues"); - - TextView textView10 = findViewById(R.id.textView10); - textView10.setText(new Boolean(booleanArray[0]).toString()); - - TextView textView11 = findViewById(R.id.h2_textview); - textView11.setText(new Boolean(booleanArray[1]).toString()); - - TextView textView12 = findViewById(R.id.h1_textview); - textView12.setText(new Boolean(booleanArray[2]).toString()); - - TextView textView13 = findViewById(R.id.textView13); - textView13.setText(new Boolean(booleanArray[3]).toString()); - - TextView textView14 = findViewById(R.id.textView14); - textView14.setText(new Boolean(booleanArray[4]).toString()); - - TextView textView15 = findViewById(R.id.textView15); - textView15.setText(new Boolean(booleanArray[5]).toString()); - - TextView textView16 = findViewById(R.id.textView16); - textView16.setText(new Boolean(booleanArray[6]).toString()); - - TextView textView17 = findViewById(R.id.textView17); - textView17.setText(new Boolean(booleanArray[7]).toString()); - - TextView textView18 = findViewById(R.id.textView18); - textView18.setText(new Boolean(booleanArray[8]).toString()); - - TextView textView19 = findViewById(R.id.textView19); - textView19.setText(new Boolean(booleanArray[9]).toString()); - - TextView textView20 = findViewById(R.id.textView20); - textView20.setText(new Boolean(booleanArray[10]).toString()); - - TextView textView21 = findViewById(R.id.textView21); - textView21.setText(new Boolean(booleanArray[11]).toString()); - } - }; -} diff --git a/app/src/main/java/com/example/user/myapp/GlobalState.java b/app/src/main/java/com/example/user/myapp/GlobalState.java deleted file mode 100644 index a0a3d94..0000000 --- a/app/src/main/java/com/example/user/myapp/GlobalState.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.example.user.myapp; - -import android.app.Application; - -import com.ghgande.j2mod.modbus.facade.ModbusTCPMaster; -import com.ghgande.j2mod.modbus.net.TCPMasterConnection; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; - -public class GlobalState extends Application { - - private String ipAddress = "172.16.202.14"; - private int port = 502; - private HashMap mapMappingValue = new HashMap(); - // - public enum InputConfig { - Q_COIL(8192, 8), - VM_COIL2 (1, 8), - VM_COIL3 (64, 8), - AI_IR(0, 2), - I_DI(0, 12); - - private int startReference; - private int count; - - InputConfig (int startReference, int count) { - this.startReference = startReference; - this.count = count; - } - - - // getter/setter - public int getStartReference() { - return startReference; - } - - public int getCount() { - return count; - } - } - - public HashMap getMapMappingValue() { - initMappingValue(); - return mapMappingValue; - } - - // getter/setter - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - private void initMappingValue () { - mapMappingValue.clear(); - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference(), InputConfig.Q_COIL.getStartReference()); // 64/8192 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 6, InputConfig.Q_COIL.getStartReference() + 1); // 70/8193 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 1, InputConfig.Q_COIL.getStartReference() + 4); // 65/8196 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 7, InputConfig.Q_COIL.getStartReference() + 5); // 71/8197 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 4, InputConfig.Q_COIL.getStartReference() + 6); // 68/8198 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 5, InputConfig.Q_COIL.getStartReference() + 7); // 69/8199 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 2, InputConfig.Q_COIL.getStartReference() + 2); // 66/8194 - mapMappingValue.put(InputConfig.VM_COIL3.getStartReference() + 3, InputConfig.Q_COIL.getStartReference() + 3); // 67/8195 - } -} diff --git a/app/src/main/java/com/example/user/myapp/MainActivity.java b/app/src/main/java/com/example/user/myapp/MainActivity.java deleted file mode 100644 index 9e15bf9..0000000 --- a/app/src/main/java/com/example/user/myapp/MainActivity.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.example.user.myapp; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -public class MainActivity extends AppCompatActivity { - - private Handler handlerCoil; - private Handler handlerDiscreteInput; - - private GlobalState state; - private static final Integer REFRESH_DELAY = 1000; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - state = (GlobalState) getApplicationContext(); - // listener - LocalBroadcastManager.getInstance(this).registerReceiver(coilMessageReceiver, new IntentFilter("readOnlyCoil")); - LocalBroadcastManager.getInstance(this).registerReceiver(discreteInputMessageReceiver, new IntentFilter("readOnlyDiscreteInput")); - // handler - handlerCoil = new Handler(); - handlerCoil.post(refreshCoil); - - handlerDiscreteInput = new Handler(); - handlerDiscreteInput.post(refreshDiscreteInput); - - setContentView(R.layout.activity_main); - - // swipe event - OnSwipeTouchListener onSwipeTouchListener = new OnSwipeTouchListener(MainActivity.this) { - @Override - public void onSwipeLeft() { - Intent nextIntent = new Intent(MainActivity.this, ManualDriveActivity.class); - startActivity(nextIntent); - // handlerCoil.removeCallbacks(refreshCoil); - // handlerDiscreteInput.removeCallbacks(refreshDiscreteInput); - } - }; - - final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this.findViewById(android.R.id.content)).getChildAt(0); - viewGroup.setOnTouchListener(onSwipeTouchListener); - } - - @Override - public void onPause () { - super.onPause(); - handlerCoil.removeCallbacks(refreshCoil); - handlerDiscreteInput.removeCallbacks(refreshDiscreteInput); - } - - @Override - public void onResume () { - super.onResume(); - handlerCoil.post(refreshCoil); - handlerDiscreteInput.post(refreshDiscreteInput); - } - - Runnable refreshCoil = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.Q_COIL.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.Q_COIL.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyCoil"); - getApplicationContext().startService(serviceIntent); - - handlerCoil.postDelayed(this, REFRESH_DELAY); - } - }; - - Runnable refreshDiscreteInput = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.discrete.input"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.I_DI.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.I_DI.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyDiscreteInput"); - getApplicationContext().startService(serviceIntent); - - handlerDiscreteInput.postDelayed(this, REFRESH_DELAY); - } - }; - - // on message receive, update the lights with dependings on coil value - private BroadcastReceiver coilMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle bundle = intent.getExtras(); - boolean[] booleanArray = bundle.getBooleanArray("coilValues"); - - // ============= Light =============== - ImageView pu1StatusLightOn = findViewById(R.id.pu1_status_light_on_mainview); - ImageView pu1StatusLightOff = findViewById(R.id.pu1_status_light_off_mainview); - ImageView pu2StatusLightOn = findViewById(R.id.pu2_status_light_on_mainview); - ImageView pu2StatusLightOff = findViewById(R.id.pu2_status_light_off_mainview); - - ImageView sp1StatusLightOn = findViewById(R.id.sp1_status_light_on_mainview); - ImageView sp1StatusLightOff = findViewById(R.id.sp1_status_light_off_mainview); - ImageView b1StatusLightOn = findViewById(R.id.b1_status_light_on_mainview); - ImageView b1StatusLightOff = findViewById(R.id.b1_status_light_off_mainview); - - ImageView m1StatusLightOn = findViewById(R.id.m1_status_light_on_mainview); - ImageView m1StatusLightOff = findViewById(R.id.m1_status_light_off_mainview); - ImageView m2StatusLightOn = findViewById(R.id.m2_status_light_on_mainview); - ImageView m2StatusLightOff = findViewById(R.id.m2_status_light_off_mainview); - - // ============== Coil : Range 8192 - 8199 ================= - // 8199 - if (booleanArray[7]) { - b1StatusLightOn.setVisibility(View.VISIBLE); - b1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - b1StatusLightOn.setVisibility(View.INVISIBLE); - b1StatusLightOff.setVisibility(View.VISIBLE); - } - - // 8194 - if (booleanArray[2]) { - m1StatusLightOn.setVisibility(View.VISIBLE); - m1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - m1StatusLightOn.setVisibility(View.INVISIBLE); - m1StatusLightOff.setVisibility(View.VISIBLE); - } - - // 8195 - if (booleanArray[3]) { - m2StatusLightOn.setVisibility(View.VISIBLE); - m2StatusLightOff.setVisibility(View.INVISIBLE); - } else { - m2StatusLightOn.setVisibility(View.INVISIBLE); - m2StatusLightOff.setVisibility(View.VISIBLE); - } - - // 8196 - if (booleanArray[4]) { - pu1StatusLightOn.setVisibility(View.VISIBLE); - pu1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - pu1StatusLightOn.setVisibility(View.INVISIBLE); - pu1StatusLightOff.setVisibility(View.VISIBLE); - } - - // 8197 - if (booleanArray[5]) { - pu2StatusLightOn.setVisibility(View.VISIBLE); - pu2StatusLightOff.setVisibility(View.INVISIBLE); - } else { - pu2StatusLightOn.setVisibility(View.INVISIBLE); - pu2StatusLightOff.setVisibility(View.VISIBLE); - } - - // 8198 - if (booleanArray[6]) { - sp1StatusLightOn.setVisibility(View.VISIBLE); - sp1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - sp1StatusLightOn.setVisibility(View.INVISIBLE); - sp1StatusLightOff.setVisibility(View.VISIBLE); - } - } - }; - - private BroadcastReceiver discreteInputMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle bundle = intent.getExtras(); - boolean[] booleanArray = bundle.getBooleanArray("discreteInputValues"); - - // Lights - ImageView h1StatusLightOn = findViewById(R.id.h1_status_light_on_mainview); - ImageView h1StatusLightOff = findViewById(R.id.h1_status_light_off_mainview); - ImageView h2StatusLightOn = findViewById(R.id.h2_status_light_on_mainview); - ImageView h2StatusLightOff = findViewById(R.id.h2_status_light_off_mainview); - - ImageView ind1StatusLightOn = findViewById(R.id.ind1_status_light_on_mainview); - ImageView ind1StatusLightOff = findViewById(R.id.ind1_status_light_off_mainview); - ImageView ls5StatusLightOn = findViewById(R.id.ls5_status_light_on_mainview); - ImageView ls5StatusLightOff = findViewById(R.id.ls5_status_light_off_mainview); - ImageView ls1StatusLightOn = findViewById(R.id.ls1_status_light_on_mainview); - ImageView ls1StatusLightOff = findViewById(R.id.ls1_status_light_off_mainview); - ImageView ls4StatusLightOn = findViewById(R.id.ls4_status_light_on_mainview); - ImageView ls4StatusLightOff = findViewById(R.id.ls4_status_light_off_mainview); - - // ============ Discrete Input : Range 0 - 11 ======================== - // di 1 - if (booleanArray[1]) { - h1StatusLightOff.setVisibility(View.VISIBLE); - } else { - h1StatusLightOff.setVisibility(View.INVISIBLE); - } - - // di 2 - if (booleanArray[2]) { - h1StatusLightOn.setVisibility(View.VISIBLE); - } else { - h1StatusLightOn.setVisibility(View.INVISIBLE); - } - - // di 10 - if (booleanArray[10]) { - h2StatusLightOff.setVisibility(View.VISIBLE); - } else { - h2StatusLightOff.setVisibility(View.INVISIBLE); - } - - // di 9 - if (booleanArray[9]) { - h2StatusLightOn.setVisibility(View.VISIBLE); - } else { - h2StatusLightOn.setVisibility(View.INVISIBLE); - } - - // di 11 - if (booleanArray[11]) { - ind1StatusLightOff.setVisibility(View.INVISIBLE); - ind1StatusLightOn.setVisibility(View.VISIBLE); - } else { - ind1StatusLightOff.setVisibility(View.VISIBLE); - ind1StatusLightOn.setVisibility(View.INVISIBLE); - } - - // di 4 - if (booleanArray[4]) { - ls5StatusLightOff.setVisibility(View.INVISIBLE); - ls5StatusLightOn.setVisibility(View.VISIBLE); - } else { - ls5StatusLightOff.setVisibility(View.VISIBLE); - ls5StatusLightOn.setVisibility(View.INVISIBLE); - } - - // di 0 - if (booleanArray[0]) { - ls1StatusLightOff.setVisibility(View.INVISIBLE); - ls1StatusLightOn.setVisibility(View.VISIBLE); - } else { - ls1StatusLightOff.setVisibility(View.VISIBLE); - ls1StatusLightOn.setVisibility(View.INVISIBLE); - } - - // di 3 - if (booleanArray[3]) { - ls4StatusLightOff.setVisibility(View.INVISIBLE); - ls4StatusLightOn.setVisibility(View.VISIBLE); - } else { - ls4StatusLightOff.setVisibility(View.VISIBLE); - ls4StatusLightOn.setVisibility(View.INVISIBLE); - } - } - }; -} - diff --git a/app/src/main/java/com/example/user/myapp/ManualDriveActivity.java b/app/src/main/java/com/example/user/myapp/ManualDriveActivity.java deleted file mode 100644 index db74488..0000000 --- a/app/src/main/java/com/example/user/myapp/ManualDriveActivity.java +++ /dev/null @@ -1,382 +0,0 @@ -package com.example.user.myapp; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.view.MotionEvent; -import android.view.View; -import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.ToggleButton; - -import java.util.HashMap; -import java.util.Map; - -public class ManualDriveActivity extends AppCompatActivity { - private GlobalState state; - private Handler coilHandler; - private Handler manualModeCheckHandler; - - private HashMap mapCoilCheckStatus = new HashMap <> (); - private HashMap mapButtonCoil = new HashMap<>(); - private boolean manualMode = false; - - private void initMap () { - mapCoilCheckStatus.put(64, false); - mapCoilCheckStatus.put(70, false); - mapCoilCheckStatus.put(65, false); - mapCoilCheckStatus.put(71, false); - mapCoilCheckStatus.put(68, false); - mapCoilCheckStatus.put(69, false); - mapCoilCheckStatus.put(66, false); - mapCoilCheckStatus.put(67, false); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - state = (GlobalState) getApplicationContext(); - initMap(); // initialise the value of the coil toggle state + the corresponding coil to button - - setContentView(R.layout.activity_manual_drive); - - ToggleButton h1ControlButton =findViewById(R.id.h1_control_button); - ToggleButton h2ControlButton = findViewById(R.id.h2_control_button); - ToggleButton pu1ControlButton = findViewById(R.id.pu1_control_button); - ToggleButton pu2ControlButton = findViewById(R.id.pu2_control_button); - ToggleButton sp1ControlButton = findViewById(R.id.sp1_control_button); - ToggleButton b1ControlButton = findViewById(R.id.b1_control_button); - ToggleButton m1ControlButton = findViewById(R.id.m1_control_button); - ToggleButton m2ControlButton = findViewById(R.id.m2_control_button); - - mapButtonCoil.put(h1ControlButton, 64); - mapButtonCoil.put(h2ControlButton, 72); - mapButtonCoil.put(pu1ControlButton, 65); - mapButtonCoil.put(pu2ControlButton, 73); - mapButtonCoil.put(sp1ControlButton, 68); - mapButtonCoil.put(b1ControlButton, 69); - mapButtonCoil.put(m1ControlButton, 66); - mapButtonCoil.put(m2ControlButton, 67); - - - - LocalBroadcastManager.getInstance(this).registerReceiver(coilWriterMessageReceiver, new IntentFilter("readVmCoil2")); - // LocalBroadcastManager.getInstance(this).registerReceiver(coilWriterMessageReceiver, new IntentFilter("checkCoilValue")); - LocalBroadcastManager.getInstance(this).registerReceiver(coilMessageReceiver, new IntentFilter("readOnlyCoil")); - - // manual drive button - ToggleButton manualDriveOverrideButton = (ToggleButton) findViewById(R.id.manual_override_button); - manualDriveOverrideButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - // writing the value true - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("write.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.VM_COIL2.getStartReference()); - serviceIntent.putExtra("extra.bit", true); - serviceIntent.putExtra("extra.intent.name", "readVmCoil2"); - serviceIntent.putExtra("extra.is.basic.coil", false); - getApplicationContext().startService(serviceIntent); - } else { - // writing the value false - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("write.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.VM_COIL2.getStartReference()); - serviceIntent.putExtra("extra.bit", false); - serviceIntent.putExtra("extra.intent.name", "readVmCoil2"); - serviceIntent.putExtra("extra.is.basic.coil", false); - getApplicationContext().startService(serviceIntent); - } - } - }); - - // for each toggle button, set the event - for (Map.Entry entry : mapButtonCoil.entrySet()) { - final ToggleButton button = entry.getKey(); - final Integer coilToWrite = entry.getValue(); - button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked && manualMode) { - // writing the value true - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("write.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", coilToWrite); - serviceIntent.putExtra("extra.bit", true); - serviceIntent.putExtra("extra.intent.name", "writeBit"); - serviceIntent.putExtra("extra.is.basic.coil", true); - getApplicationContext().startService(serviceIntent); - mapCoilCheckStatus.put(coilToWrite, true); - } else { - // writing the value false - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("write.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", coilToWrite); - serviceIntent.putExtra("extra.bit", false); - serviceIntent.putExtra("extra.intent.name", "writeBit"); - serviceIntent.putExtra("extra.is.basic.coil", true); - getApplicationContext().startService(serviceIntent); - mapCoilCheckStatus.put(coilToWrite, false); - } - } - }); - } - } - - @Override - protected void onStart () { - super.onStart(); - coilHandler = new Handler(); - coilHandler.post(refreshCoil); - - manualModeCheckHandler = new Handler(); - manualModeCheckHandler.post(checkManualMockStatus) ; - } - - private BroadcastReceiver coilWriterMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - boolean isManualModeActivated = intent.getBooleanExtra("coil", false); - if (isManualModeActivated) { - manualMode = true; - } else { - manualMode = false; - } - } - }; - - private Runnable checkManualMockStatus = new Runnable() { - @Override - public void run() { - ToggleButton h1ControlButton = findViewById(R.id.h1_control_button); - ToggleButton h2ControlButton = findViewById(R.id.h2_control_button); - Button pu1ControlButton = findViewById(R.id.pu1_control_button); - Button pu2ControlButton = findViewById(R.id.pu2_control_button); - Button sp1ControlButton = findViewById(R.id.sp1_control_button); - Button b1ControlButton = findViewById(R.id.b1_control_button); - ToggleButton m1ControlButton = findViewById(R.id.m1_control_button); - ToggleButton m2ControlButton = findViewById(R.id.m2_control_button); - - // ============= Light =============== - ImageView manualLightOn = findViewById(R.id.manual_override_status_light_on); - ImageView manualLightOff = findViewById(R.id.manual_override_status_light_off); - - ImageView h1StatusLightOn = findViewById(R.id.h1_status_light_on); - ImageView h1StatusLightOff = findViewById(R.id.h1_status_light_off); - ImageView h2StatusLightOn = findViewById(R.id.h2_status_light_on); - ImageView h2StatusLightOff = findViewById(R.id.h2_status_light_off); - - ImageView pu1StatusLightOn = findViewById(R.id.pu1_status_light_on); - ImageView pu1StatusLightOff = findViewById(R.id.pu1_status_light_off); - ImageView pu2StatusLightOn = findViewById(R.id.pu2_status_light_on); - ImageView pu2StatusLightOff = findViewById(R.id.pu2_status_light_off); - - ImageView sp1StatusLightOn = findViewById(R.id.sp1_status_light_on); - ImageView sp1StatusLightOff = findViewById(R.id.sp1_status_light_off); - ImageView b1StatusLightOn = findViewById(R.id.b1_status_light_on); - ImageView b1StatusLightOff = findViewById(R.id.b1_status_light_off); - - ImageView m1StatusLightOn = findViewById(R.id.m1_status_light_on); - ImageView m1StatusLightOff = findViewById(R.id.m1_status_light_off); - ImageView m2StatusLightOn = findViewById(R.id.m2_status_light_on); - ImageView m2StatusLightOff = findViewById(R.id.m2_status_light_off); - - if (!manualMode) { - manualLightOn.setVisibility(View.INVISIBLE); - manualLightOff.setVisibility(View.VISIBLE); - - h1ControlButton.setEnabled(false); - h2ControlButton.setEnabled(false); - m1ControlButton.setEnabled(false); - m2ControlButton.setEnabled(false); - pu1ControlButton.setEnabled(false); - pu2ControlButton.setEnabled(false); - sp1ControlButton.setEnabled(false); - b1ControlButton.setEnabled(false); - - manualLightOn.setVisibility(View.INVISIBLE); - manualLightOff.setVisibility(View.VISIBLE); - // switch all off - h1StatusLightOn.setVisibility(View.INVISIBLE); - h1StatusLightOff.setVisibility(View.INVISIBLE); - h2StatusLightOn.setVisibility(View.INVISIBLE); - h2StatusLightOff.setVisibility(View.INVISIBLE); - m1StatusLightOn.setVisibility(View.INVISIBLE); - m1StatusLightOff.setVisibility(View.INVISIBLE); - m2StatusLightOn.setVisibility(View.INVISIBLE); - m2StatusLightOff.setVisibility(View.INVISIBLE); - pu1StatusLightOn.setVisibility(View.INVISIBLE); - pu1StatusLightOff.setVisibility(View.INVISIBLE); - pu2StatusLightOn.setVisibility(View.INVISIBLE); - pu2StatusLightOff.setVisibility(View.INVISIBLE); - sp1StatusLightOn.setVisibility(View.INVISIBLE); - sp1StatusLightOff.setVisibility(View.INVISIBLE); - b1StatusLightOn.setVisibility(View.INVISIBLE); - b1StatusLightOff.setVisibility(View.INVISIBLE); - } - manualModeCheckHandler.postDelayed(this, 1000); - } - }; - - private Runnable refreshCoil = new Runnable() { - @Override - public void run() { - Intent serviceIntent = new Intent(getApplicationContext(), MyIntentService.class); - serviceIntent.setAction("read.coil"); - serviceIntent.putExtra("extra.ip.address", state.getIpAddress()); - serviceIntent.putExtra("extra.ip.port", state.getPort()); - serviceIntent.putExtra("extra.ref", GlobalState.InputConfig.Q_COIL.getStartReference()); - serviceIntent.putExtra("extra.count", GlobalState.InputConfig.Q_COIL.getCount()); - serviceIntent.putExtra("extra.intent.name", "readOnlyCoil"); - getApplicationContext().startService(serviceIntent); - - coilHandler.postDelayed(this, 3000); - } - }; - - // on message receive, update the view with values - private BroadcastReceiver coilMessageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - Bundle bundle = intent.getExtras(); - boolean[] booleanArray = bundle.getBooleanArray("coilValues"); - - // ========== Button ============ - ToggleButton h1ControlButton = findViewById(R.id.h1_control_button); - ToggleButton h2ControlButton = findViewById(R.id.h2_control_button); - Button pu1ControlButton = findViewById(R.id.pu1_control_button); - Button pu2ControlButton = findViewById(R.id.pu2_control_button); - Button sp1ControlButton = findViewById(R.id.sp1_control_button); - Button b1ControlButton = findViewById(R.id.b1_control_button); - ToggleButton m1ControlButton = findViewById(R.id.m1_control_button); - ToggleButton m2ControlButton = findViewById(R.id.m2_control_button); - - // ============= Light =============== - ImageView manualLightOn = findViewById(R.id.manual_override_status_light_on); - ImageView manualLightOff = findViewById(R.id.manual_override_status_light_off); - - ImageView h1StatusLightOn = findViewById(R.id.h1_status_light_on); - ImageView h1StatusLightOff = findViewById(R.id.h1_status_light_off); - ImageView h2StatusLightOn = findViewById(R.id.h2_status_light_on); - ImageView h2StatusLightOff = findViewById(R.id.h2_status_light_off); - - ImageView pu1StatusLightOn = findViewById(R.id.pu1_status_light_on); - ImageView pu1StatusLightOff = findViewById(R.id.pu1_status_light_off); - ImageView pu2StatusLightOn = findViewById(R.id.pu2_status_light_on); - ImageView pu2StatusLightOff = findViewById(R.id.pu2_status_light_off); - - ImageView sp1StatusLightOn = findViewById(R.id.sp1_status_light_on); - ImageView sp1StatusLightOff = findViewById(R.id.sp1_status_light_off); - ImageView b1StatusLightOn = findViewById(R.id.b1_status_light_on); - ImageView b1StatusLightOff = findViewById(R.id.b1_status_light_off); - - ImageView m1StatusLightOn = findViewById(R.id.m1_status_light_on); - ImageView m1StatusLightOff = findViewById(R.id.m1_status_light_off); - ImageView m2StatusLightOn = findViewById(R.id.m2_status_light_on); - ImageView m2StatusLightOff = findViewById(R.id.m2_status_light_off); - - if (manualMode) { - h1ControlButton.setEnabled(true); - h2ControlButton.setEnabled(true); - m1ControlButton.setEnabled(true); - m2ControlButton.setEnabled(true); - pu1ControlButton.setEnabled(true); - pu2ControlButton.setEnabled(true); - sp1ControlButton.setEnabled(true); - b1ControlButton.setEnabled(true); - - manualLightOn.setVisibility(View.VISIBLE); - manualLightOff.setVisibility(View.INVISIBLE); - // lightning - // ======== h1 ========= - if (booleanArray[0] == true) { - h1StatusLightOn.setVisibility(View.VISIBLE); - h1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - h1StatusLightOn.setVisibility(View.INVISIBLE); - h1StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== h2 ====== - if (booleanArray[1] == true) { - h2StatusLightOn.setVisibility(View.VISIBLE); - h2StatusLightOff.setVisibility(View.INVISIBLE); - } else { - h2StatusLightOn.setVisibility(View.INVISIBLE); - h2StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== m1 ====== - if (booleanArray[2] == true) { - m1StatusLightOn.setVisibility(View.VISIBLE); - m1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - m1StatusLightOn.setVisibility(View.INVISIBLE); - m1StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== m2 ====== - if (booleanArray[3] == true) { - m2StatusLightOn.setVisibility(View.VISIBLE); - m2StatusLightOff.setVisibility(View.INVISIBLE); - } else { - m2StatusLightOn.setVisibility(View.INVISIBLE); - m2StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== pu1 ====== - if (booleanArray[4] == true) { - pu1StatusLightOn.setVisibility(View.VISIBLE); - pu1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - pu1StatusLightOn.setVisibility(View.INVISIBLE); - pu1StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== pu2 ====== - if (booleanArray[5] == true) { - pu2StatusLightOn.setVisibility(View.VISIBLE); - pu2StatusLightOff.setVisibility(View.INVISIBLE); - } else { - pu2StatusLightOn.setVisibility(View.INVISIBLE); - pu2StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== m2 ====== - if (booleanArray[6] == true) { - sp1StatusLightOn.setVisibility(View.VISIBLE); - sp1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - sp1StatusLightOn.setVisibility(View.INVISIBLE); - sp1StatusLightOff.setVisibility(View.VISIBLE); - } - - // ======== m2 ====== - if (booleanArray[7] == true) { - b1StatusLightOn.setVisibility(View.VISIBLE); - b1StatusLightOff.setVisibility(View.INVISIBLE); - } else { - b1StatusLightOn.setVisibility(View.INVISIBLE); - b1StatusLightOff.setVisibility(View.VISIBLE); - } - } - } - }; -} diff --git a/app/src/main/java/com/example/user/myapp/MeasurementActivity.java b/app/src/main/java/com/example/user/myapp/MeasurementActivity.java deleted file mode 100644 index bf1cf54..0000000 --- a/app/src/main/java/com/example/user/myapp/MeasurementActivity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.example.user.myapp; - -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; - -public class MeasurementActivity extends AppCompatActivity { - - Boolean myBoolean = false; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_measurement); - } - - - public boolean toggle () { - return myBoolean ? false: true; - } -} diff --git a/app/src/main/java/com/example/user/myapp/MyIntentService.java b/app/src/main/java/com/example/user/myapp/MyIntentService.java deleted file mode 100644 index b0ca2ad..0000000 --- a/app/src/main/java/com/example/user/myapp/MyIntentService.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.example.user.myapp; - -import android.app.IntentService; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.content.LocalBroadcastManager; - -import com.ghgande.j2mod.modbus.facade.ModbusTCPMaster; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.util.BitVector; - -import java.util.ArrayList; -import java.util.List; - -/** - * An {@link IntentService} subclass for handling asynchronous task requests in - * a service on a separate handler thread. - *

- * TODO: Customize class - update intent actions, extra parameters and static - * helper methods. - */ -public class MyIntentService extends IntentService { - - // read action - private static final String ACTION_READ_COIL = "read.coil"; - private static final String ACTION_READ_INPUT_REGISTER = "read.input.register"; - private static final String ACTION_READ_DISCRETE_INPUT = "read.discrete.input"; - - // write action - private static final String ACTION_WRITE_COIL = "write.coil"; - - private static final String ACTION_CHECK_COIL = "check.coil"; - - private ModbusTCPMaster master; - - // TODO: Rename parameters - private static final String EXTRA_IP_ADDRESS = "extra.ip.address"; - private static final String EXTRA_PORT = "extra.ip.port"; - private static final String EXTRA_REF = "extra.ref"; - private static final String EXTRA_COUNT = "extra.count"; - private static final String EXTRA_INTENT_NAME = "extra.intent.name"; - - private static final String EXTRA_BIT_TO_SET = "extra.bit"; - //turns out modbus on siemens logo is crap and isnt responding for at least 50ms - private static final Integer CAP_WAIT_TIME = 100; - //this is not a type, idiot. - - public MyIntentService() { - super("MyIntentService"); - } - - private void sendBooleanListToActivity(List booleanList, String intentName, String bundleName) { - Intent intent = new Intent(intentName); - Bundle bundle = new Bundle(); - bundle.putBooleanArray(bundleName, toPrimitiveArray(booleanList)); - intent.putExtras(bundle); - sendLocationBroadcast(intent); - } - - private void sendIntegerListToActivity (ArrayList integerList, String intentName) { - Intent intent = new Intent(intentName); - Bundle bundle = new Bundle(); - - bundle.putIntegerArrayList("irValues", integerList); - intent.putExtras(bundle); - sendLocationBroadcast(intent); - } - - private void sendLocationBroadcast(Intent intent) { - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - } - - public void readDiscreteInputAction (String ipAddress, int port, int ref, int count, String intentReceiveName) { - try { - master = new ModbusTCPMaster(ipAddress, port); - master.connect(); - - BitVector bv = master.readInputDiscretes(ref, count); - List listBooleanBit = new ArrayList<>(); - for (int i = 0; i < count; i++) { - System.out.println(i+" discret input "+bv.getBit(i)); - listBooleanBit.add(bv.getBit(i)); - } - sendBooleanListToActivity(listBooleanBit, intentReceiveName, "discreteInputValues"); - Thread.sleep(CAP_WAIT_TIME); - master.disconnect(); - } catch (Exception e) { - System.out.println("Exception in reading discrete input " + e); - } - } - - public void readCoilAction (String ipAddress, int port, int ref, int count, String intentReceiveName) { - try { - master = new ModbusTCPMaster(ipAddress, port); - master.connect(); - - BitVector bv = master.readCoils(ref,count); - List listBooleanBit = new ArrayList<>(); - for (int i = 0; i < count; i++) { - System.out.println(i+" coil "+bv.getBit(i)); - listBooleanBit.add(bv.getBit(i)); - } - sendBooleanListToActivity(listBooleanBit, intentReceiveName, "coilValues"); - Thread.sleep(CAP_WAIT_TIME); - master.disconnect(); - } catch (Exception e) { - System.out.println("Exception in reading coil " + e); - } - } - - public void readInputRegisterAction (String ipAddress, int port, int ref, int count, String intentReceiveName) { - try { - master = new ModbusTCPMaster(ipAddress, port); - master.connect(); - - InputRegister [] inputRegisters = master.readInputRegisters(ref, count); - ArrayList listIntegerInputRegister = new ArrayList<>(); - for (InputRegister ir : inputRegisters) { - listIntegerInputRegister.add(ir.getValue()); - System.out.println(ir.getValue()+" input register "+Math.random()); - } - sendIntegerListToActivity (listIntegerInputRegister, intentReceiveName); - Thread.sleep(CAP_WAIT_TIME); - master.disconnect(); - } catch (Exception e) { - System.out.println("Exception in reading input register " + e); - } - } - - public void writeCoilAction (String ipAddress, int port, int ref, boolean value, String intentReceiveName, boolean withCheck) { - try { - master = new ModbusTCPMaster(ipAddress, port); - master.connect(); - // writing the value - boolean writtenValue = master.writeCoil(ref, value); - if (withCheck) { - System.out.println("I wrote " + writtenValue + " to coil " + ref); - Thread.sleep(CAP_WAIT_TIME); - - GlobalState state = (GlobalState) getApplicationContext(); - - int coilToRead = state.getMapMappingValue().get(ref); - System.out.println("Checking the value of coil "+coilToRead); - boolean currentValue = master.readCoils(coilToRead, 1).getBit(0); - sendNewBitValueToActivity(currentValue, intentReceiveName); - } else { - System.out.println("I switched the manual mode to " + writtenValue); - sendNewBitValueToActivity(writtenValue, intentReceiveName); - } - Thread.sleep(CAP_WAIT_TIME); - master.disconnect(); - } catch (Exception e) { - System.out.println("Exception in writing coil " + e); - } - } - - private void sendNewBitValueToActivity (boolean newValue, String intentReceive) { - Intent intent = new Intent(intentReceive); - intent.putExtra("coil", newValue); - sendLocationBroadcast(intent); - } - - @Override - protected void onHandleIntent(Intent intent) { - if (intent != null) { - final String action = intent.getAction(); - final String ipAddress = intent.getStringExtra(EXTRA_IP_ADDRESS); - final int port = intent.getIntExtra(EXTRA_PORT, 502); - final int ref = intent.getIntExtra(EXTRA_REF, 8192); - final int count = intent.getIntExtra(EXTRA_COUNT, 8); - final String intentName = intent.getStringExtra(EXTRA_INTENT_NAME); - - // for write - final Boolean value = intent.getBooleanExtra(EXTRA_BIT_TO_SET, false); - - final Boolean withCheck = intent.getBooleanExtra("extra.is.basic.coil", false); - - switch(action) { - case ACTION_READ_DISCRETE_INPUT: - readDiscreteInputAction (ipAddress, port, ref, count, intentName); - break; - case ACTION_READ_COIL : - readCoilAction(ipAddress, port, ref, count, intentName); - break; - case ACTION_READ_INPUT_REGISTER : - readInputRegisterAction (ipAddress, port,ref, count, intentName); - break; - case ACTION_WRITE_COIL: - writeCoilAction(ipAddress, port, ref, value, intentName, withCheck); - break; - } - } - } - - - private boolean[] toPrimitiveArray(final List booleanList) { - final boolean[] primitives = new boolean[booleanList.size()]; - int index = 0; - for (Boolean object : booleanList) { - primitives[index++] = object; - } - return primitives; - } -} diff --git a/app/src/main/java/com/example/user/myapp/OnSwipeTouchListener.java b/app/src/main/java/com/example/user/myapp/OnSwipeTouchListener.java deleted file mode 100644 index 88cd3c5..0000000 --- a/app/src/main/java/com/example/user/myapp/OnSwipeTouchListener.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.example.user.myapp; - -import android.content.Context; -import android.view.GestureDetector; -import android.view.GestureDetector.SimpleOnGestureListener; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; - -public class OnSwipeTouchListener implements OnTouchListener { - - - private final GestureDetector gestureDetector; - private Context context; - - /* (non-Javadoc) - * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent) - */ - public boolean onTouch(final View view, final MotionEvent motionEvent) { - return gestureDetector.onTouchEvent(motionEvent); - } - - /** - * Gets the gesture detector. - * - * @return the gesture detector - */ - public GestureDetector getGestureDetector() { - return gestureDetector; - } - - /** - * Instantiates a new on swipe touch listener. - * - * @param context the context - */ - public OnSwipeTouchListener(Context context) { - super(); - this.context = context; - gestureDetector = new GestureDetector(context, new GestureListener()); - } - - private final class GestureListener extends SimpleOnGestureListener { - - private static final int SWIPE_THRESHOLD = 100; - private static final int SWIPE_VELOCITY_THRESHOLD = 100; - - /* (non-Javadoc) - * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) - */ - @Override - public boolean onDown(MotionEvent e) { - return true; - } - - /* (non-Javadoc) - * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float) - */ - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - boolean result = false; - try { - float diffY = e2.getRawY() - e1.getRawY(); - float diffX = e2.getRawX() - e1.getRawX(); - if ((Math.abs(diffX) - Math.abs(diffY)) > SWIPE_THRESHOLD) { - if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { - if (diffX > 0) { - onSwipeRight(); - } else { - onSwipeLeft(); - } - } - } else { - if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { - if (diffY > 0) { - onSwipeBottom(); - } else { - onSwipeTop(); - } - } - } - } catch (Exception e) { - - } - return result; - } - } - - /** - * On swipe right. - */ - public void onSwipeRight() { - } - - /** - * On swipe left. - */ - public void onSwipeLeft() { - } - - /** - * On swipe top. - */ - public void onSwipeTop() { - } - - /** - * On swipe bottom. - */ - public void onSwipeBottom() { - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/Modbus.java b/app/src/main/java/com/ghgande/j2mod/modbus/Modbus.java deleted file mode 100644 index 3ab0c71..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/Modbus.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus; - -/** - * Interface defining all constants related to the - * Modbus protocol. - * - * @author Dieter Wimberger - * @version 1.2rc1 (09/11/2004) - */ -public interface Modbus { - - /** - * Defines the class 1 function code - * for read coils. - */ - int READ_COILS = 1; - - /** - * Defines a class 1 function code - * for read input discretes. - */ - int READ_INPUT_DISCRETES = 2; - - /** - * Defines a class 1 function code - * for read holding registers - */ - int READ_HOLDING_REGISTERS = 3; - - /** - * Defines the class 0 function code - * for read multiple registers. The - * proper name is "Read Holding Registers". - */ - int READ_MULTIPLE_REGISTERS = 3; - - /** - * Defines a class 1 function code - * for read input registers. - */ - int READ_INPUT_REGISTERS = 4; - - /** - * Defines a class 1 function code - * for write coil. - */ - int WRITE_COIL = 5; - - /** - * Defines a class 1 function code - * for write single register. - */ - int WRITE_SINGLE_REGISTER = 6; - - /** - * read exception status - * - * Serial devices only. - */ - int READ_EXCEPTION_STATUS = 7; - - /** - * get serial diagnostics - * - * Serial devices only. - */ - int READ_SERIAL_DIAGNOSTICS = 8; - - /** - * get comm event counter - * - * Serial devices only. - */ - int READ_COMM_EVENT_COUNTER = 11; - - /** - * get comm event log - * - * Serial devices only. - */ - int READ_COMM_EVENT_LOG = 12; - - /** - * Defines a standard function code - * for write multiple coils. - */ - int WRITE_MULTIPLE_COILS = 15; - - /** - * Defines the class 0 function code - * for write multiple registers. - */ - int WRITE_MULTIPLE_REGISTERS = 16; - - /** - * Defines a standard function code - * for read slave ID. - */ - int REPORT_SLAVE_ID = 17; - - /** - * read file record - */ - int READ_FILE_RECORD = 20; - - /** - * write file record - */ - int WRITE_FILE_RECORD = 21; - - /** - * mask write register - * - * Update a single register using its current value and an AND - * and OR mask. - */ - int MASK_WRITE_REGISTER = 22; - - /** - * read / write multiple registers - * - * Write some number of registers, then read some number of - * potentially other registers back. - */ - int READ_WRITE_MULTIPLE = 23; - - /** - * read FIFO queue - * - * Read from a FIFO queue. - */ - int READ_FIFO_QUEUE = 24; - - /** - * Defines the function code for reading - * encapsulated data, such as vendor information. - */ - int READ_MEI = 43; - int READ_MEI_VENDOR_INFO = 14; - - /** - * Defines the byte representation of the coil state on. - */ - int COIL_ON = (byte)255; - - /** - * Defines the byte representation of the coil state pos. - */ - int COIL_OFF = 0; - - /** - * Defines the word representation of the coil state on. - */ - byte[] COIL_ON_BYTES = {(byte)COIL_ON, (byte)COIL_OFF}; - - /** - * Defines the word representation of the coil state pos. - */ - byte[] COIL_OFF_BYTES = {(byte)COIL_OFF, (byte)COIL_OFF}; - - /** - * Defines the maximum number of bits in multiple read/write - * of input discretes or coils (2000). - */ - int MAX_BITS = 2000; - - /** - * Defines the Modbus slave exception offset that is added to the - * function code, to flag an exception. - */ - int EXCEPTION_OFFSET = 128; //the last valid function code is 127 - - /** - * Defines the Modbus slave exception type illegal function. - * This exception code is returned if the slave: - *

    - *
  • does not implement the function code or
  • - *
  • is not in a state that allows it to process the function
  • - *
- */ - int ILLEGAL_FUNCTION_EXCEPTION = 1; - - /** - * Defines the Modbus slave exception type illegal data address. - * This exception code is returned if the reference: - *
    - *
  • does not exist on the slave or
  • - *
  • the combination of reference and length exceeds the bounds - * of the existing registers. - *
  • - *
- */ - int ILLEGAL_ADDRESS_EXCEPTION = 2; - - /** - * Defines the Modbus slave exception type illegal data value. - * This exception code indicates a fault in the structure of the data values - * of a complex request, such as an incorrect implied length.
- * This code does not indicate a problem with application specific validity - * of the value. - */ - int ILLEGAL_VALUE_EXCEPTION = 3; - - /** - * Defines the Modbus slave exception type slave device failure. - * This exception code indicates a fault in the slave device itself. - */ - int SLAVE_DEVICE_FAILURE = 4; - - /** - * Defines the Modbus slave exception type slave busy. This - * exception indicates the the slave is unable to perform the operation - * because it is performing an operation which cannot be interrupted. - */ - int SLAVE_BUSY_EXCEPTION = 6; - - /** - * Defines the Modbus slave exception type negative acknowledgment. - * This exception code indicates the slave cannot perform the requested - * action. - */ - int NEGATIVE_ACKNOWLEDGEMENT = 7; - - /** - * Defines the Modbus slave exception type Gateway target failed to - * respond. This exception code indicates that a Modbus gateway - * failed to receive a response from the specified target. - */ - int GATEWAY_TARGET_NO_RESPONSE = 11; - - /** - * Defines the default port number of Modbus - * (=502). - */ - int DEFAULT_PORT = 502; - - /** - * Defines the maximum message length in bytes - * (=256). - */ - int MAX_MESSAGE_LENGTH = 256; - - /** - * Defines the default transaction identifier (=0). - */ - int DEFAULT_TRANSACTION_ID = 0; - - /** - * Defines the default protocol identifier (=0). - */ - int DEFAULT_PROTOCOL_ID = 0; - - /** - * Defines the default unit identifier (=0). - */ - int DEFAULT_UNIT_ID = 0; - - /** - * Defines the default setting for validity checking - * in transactions (=true). - */ - boolean DEFAULT_VALIDITYCHECK = true; - - /** - * Defines the default setting for I/O operation timeouts - * in milliseconds (=3000). - */ - int DEFAULT_TIMEOUT = 3000; - - /** - * Defines the sleep period between transaction retries - * in milliseconds (=200). - */ - int RETRY_SLEEP_TIME = 500; - - /** - * Defines the default reconnecting setting for - * transactions (=false). - */ - boolean DEFAULT_RECONNECTING = false; - - /** - * Defines the default amount of retires for opening - * a connection (=3). - */ - int DEFAULT_RETRIES = 5; - - /** - * Defines the default number of msec to delay before transmission
- * Inter-message delays are managed by the SerialTransaction object automatically based on the - * baud rate. Setting this value to anything other than zero will bypass that process and force - * a specific inter-message delay - * (=0). - */ - int DEFAULT_TRANSMIT_DELAY = 0; - - /** - * Defines the default number of msec to delay before transmission if not overridden by DEFAULT_TRANSMIT_DELAY - * (=2). - */ - int MINIMUM_TRANSMIT_DELAY = 2; - - /** - * The number of characters delay that must be maintained between adjacent requests on - * the same serial port (within the same transaction) - */ - double INTER_MESSAGE_GAP = 4; - - /** - * Defines the maximum value of the transaction identifier. - * - *

Note: The standard requires that the server copy whatever - * value the client provides. However, the transaction ID is being - * limited to signed 16-bit integers to prevent problems with servers - * that might incorrectly assume the value is a signed value. - */ - int MAX_TRANSACTION_ID = Short.MAX_VALUE; - - /** - * Defines the serial encoding "ASCII". - */ - String SERIAL_ENCODING_ASCII = "ascii"; - - /** - * Defines the serial encoding "RTU". - */ - String SERIAL_ENCODING_RTU = "rtu"; - - /** - * Defines the default serial encoding (ASCII). - */ - String DEFAULT_SERIAL_ENCODING = SERIAL_ENCODING_ASCII; - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusException.java b/app/src/main/java/com/ghgande/j2mod/modbus/ModbusException.java deleted file mode 100644 index 35ea753..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusException.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus; - -/** - * Superclass of all specialised exceptions in this package. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusException extends Exception { - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * Constructs a new ModbusException instance. - */ - public ModbusException() { - super(); - } - - /** - * Constructs a new ModbusException instance with the given - * message. - *

- * - * @param message the message describing this ModbusException. - */ - public ModbusException(String message) { - super(message); - } - - /** - * Constructs a new ModbusException instance with the given - * message. - *

- * - * @param message the message describing this ModbusException. - * @param values optional values of the exception - */ - public ModbusException(String message, Object... values) { - super(String.format(message, values)); - } - - /** - * Constructs a new ModbusException instance with the given - * message and underlying cause. - *

- * - * @param message the message describing this ModbusException. - * @param cause the cause (which is saved for later retrieval by the {@code getCause()} method). - * (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) - */ - public ModbusException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusIOException.java b/app/src/main/java/com/ghgande/j2mod/modbus/ModbusIOException.java deleted file mode 100644 index b0f4ba6..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusIOException.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus; - -/** - * Class that implements a ModbusIOException. Instances of this - * exception are thrown when errors in the I/O occur. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusIOException extends ModbusException { - - /** - * - */ - private static final long serialVersionUID = 1L; - private boolean eof = false; - - /** - * Constructs a new ModbusIOException instance. - */ - public ModbusIOException() { - } - - /** - * Constructs a new ModbusIOException instance with the given - * message. - *

- * - * @param message the message describing this ModbusIOException. - */ - public ModbusIOException(String message) { - super(message); - } - - /** - * Constructs a new ModbusIOException instance with the given - * message. - *

- * - * @param message the message describing this ModbusIOException. - * @param values optional values of the exception - */ - public ModbusIOException(String message, Object... values) { - super(message, values); - } - - /** - * Constructs a new ModbusIOException instance. - * - * @param b true if caused by end of stream, false otherwise. - */ - public ModbusIOException(boolean b) { - eof = b; - } - - /** - * Constructs a new ModbusIOException instance with the given - * message. - *

- * - * @param message the message describing this ModbusIOException. - * @param b true if caused by end of stream, false otherwise. - */ - public ModbusIOException(String message, boolean b) { - super(message); - eof = b; - } - - /** - * Constructs a new ModbusIOException instance with the given - * message and underlying cause. - *

- * - * @param message the message describing this ModbusIOException. - * @param cause the cause (which is saved for later retrieval by the {@code getCause()} method). - * (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) - */ - public ModbusIOException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Tests if this ModbusIOException is caused by an end of the - * stream. - *

- * - * @return true if stream ended, false otherwise. - */ - public boolean isEOF() { - return eof; - } - - /** - * Sets the flag that determines whether this ModbusIOException was - * caused by an end of the stream. - *

- * - * @param b true if stream ended, false otherwise. - */ - public void setEOF(boolean b) { - eof = b; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusSlaveException.java b/app/src/main/java/com/ghgande/j2mod/modbus/ModbusSlaveException.java deleted file mode 100644 index a57e7b0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/ModbusSlaveException.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus; - -/** - * Class that implements a ModbusSlaveException. Instances of this - * exception are thrown when the slave returns a Modbus exception. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusSlaveException extends ModbusException { - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * Instance type attribute - */ - private int type = -1; - - /** - *

- * Constructs a new ModbusSlaveException instance with the given - * type. - * - *

- * Types are defined according to the protocol specification in - * net.wimpi.modbus.Modbus. - * - * @param type the type of exception that occurred. - */ - public ModbusSlaveException(int type) { - super(); - - this.type = type; - } - - /** - * Get the exception type message associated with the given exception - * number. - * - * @param type Numerical value of the Modbus exception. - * - * @return a String indicating the type of slave exception. - */ - public static String getMessage(int type) { - switch (type) { - case 1: - return "Illegal Function"; - case 2: - return "Illegal Data Address"; - case 3: - return "Illegal Data Value"; - case 4: - return "Slave Device Failure"; - case 5: - return "Acknowledge"; - case 6: - return "Slave Device Busy"; - case 8: - return "Memory Parity Error"; - case 10: - return "Gateway Path Unavailable"; - case 11: - return "Gateway Target Device Failed to Respond"; - } - return "Error Code = " + type; - } - - /** - *

- * Returns the type of this ModbusSlaveException.
- * Types are defined according to the protocol specification in - * net.wimpi.modbus.Modbus. - * - * @return the type of this ModbusSlaveException. - */ - public int getType() { - return type; - } - - /** - *

- * Tests if this ModbusSlaveException is of a given type. - * - *

- * Types are defined according to the protocol specification in - * net.wimpi.modbus.Modbus. - * - * @param TYPE the type to test this ModbusSlaveException type - * against. - * - * @return true if this ModbusSlaveException is of the given type, - * false otherwise. - */ - public boolean isType(int TYPE) { - return (TYPE == type); - } - - /** - * Get the exception type message associated with this exception. - * - * @return a String indicating the type of slave exception. - */ - public String getMessage() { - return getMessage(type); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/facade/AbstractModbusMaster.java b/app/src/main/java/com/ghgande/j2mod/modbus/facade/AbstractModbusMaster.java deleted file mode 100644 index fd3b797..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/facade/AbstractModbusMaster.java +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.facade; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.io.ModbusTransaction; -import com.ghgande.j2mod.modbus.msg.*; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.util.BitVector; - -/** - * Modbus/TCP Master facade - common methods for all the facade implementations - * The emphasis is in making callas to Modbus devices as simple as possible - * for the most common Function Codes. - * This class makes sure that no NPE is raised and that the methods are thread-safe. - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -abstract public class AbstractModbusMaster { - - private static final int DEFAULT_UNIT_ID = 1; - - protected ModbusTransaction transaction; - private ReadCoilsRequest readCoilsRequest; - private ReadInputDiscretesRequest readInputDiscretesRequest; - private WriteCoilRequest writeCoilRequest; - private WriteMultipleCoilsRequest writeMultipleCoilsRequest; - private ReadInputRegistersRequest readInputRegistersRequest; - private ReadMultipleRegistersRequest readMultipleRegistersRequest; - private WriteSingleRegisterRequest writeSingleRegisterRequest; - private WriteMultipleRegistersRequest writeMultipleRegistersRequest; - protected int timeout = Modbus.DEFAULT_TIMEOUT; - - /** - * Sets the transaction to use - * - * @param transaction Transaction to use - */ - protected synchronized void setTransaction(ModbusTransaction transaction) { - this.transaction = transaction; - } - - /** - * Connects this ModbusTCPMaster with the slave. - * - * @throws Exception if the connection cannot be established. - */ - abstract public void connect() throws Exception; - - /** - * Disconnects this ModbusTCPMaster from the slave. - */ - abstract public void disconnect(); - - /** - * Reads a given number of coil states from the slave. - * - * Note that the number of bits in the bit vector will be - * forced to the number originally requested. - * - * @param unitId the slave unit id. - * @param ref the offset of the coil to start reading from. - * @param count the number of coil states to be read. - * - * @return a BitVector instance holding the - * received coil states. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized BitVector readCoils(int unitId, int ref, int count) throws ModbusException { - checkTransaction(); - if (readCoilsRequest == null) { - readCoilsRequest = new ReadCoilsRequest(); - } - readCoilsRequest.setUnitID(unitId); - readCoilsRequest.setReference(ref); - readCoilsRequest.setBitCount(count); - transaction.setRequest(readCoilsRequest); - transaction.execute(); - BitVector bv = ((ReadCoilsResponse) getAndCheckResponse()).getCoils(); - bv.forceSize(count); - return bv; - } - - /** - * Writes a coil state to the slave. - * - * @param unitId the slave unit id. - * @param ref the offset of the coil to be written. - * @param state the coil state to be written. - * - * @return the state of the coil as returned from the slave. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized boolean writeCoil(int unitId, int ref, boolean state) throws ModbusException { - checkTransaction(); - if (writeCoilRequest == null) { - writeCoilRequest = new WriteCoilRequest(); - } - writeCoilRequest.setUnitID(unitId); - writeCoilRequest.setReference(ref); - writeCoilRequest.setCoil(state); - transaction.setRequest(writeCoilRequest); - transaction.execute(); - return ((WriteCoilResponse) getAndCheckResponse()).getCoil(); - } - - /** - * Writes a given number of coil states to the slave. - * - * Note that the number of coils to be written is given - * implicitly, through {@link BitVector#size()}. - * - * @param unitId the slave unit id. - * @param ref the offset of the coil to start writing to. - * @param coils a BitVector which holds the coil states to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeMultipleCoils(int unitId, int ref, BitVector coils) throws ModbusException { - checkTransaction(); - if (writeMultipleCoilsRequest == null) { - writeMultipleCoilsRequest = new WriteMultipleCoilsRequest(); - } - writeMultipleCoilsRequest.setUnitID(unitId); - writeMultipleCoilsRequest.setReference(ref); - writeMultipleCoilsRequest.setCoils(coils); - transaction.setRequest(writeMultipleCoilsRequest); - transaction.execute(); - } - - /** - * Reads a given number of input discrete states from the slave. - * - * Note that the number of bits in the bit vector will be - * forced to the number originally requested. - * - * @param unitId the slave unit id. - * @param ref the offset of the input discrete to start reading from. - * @param count the number of input discrete states to be read. - * - * @return a BitVector instance holding the received input discrete - * states. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized BitVector readInputDiscretes(int unitId, int ref, int count) throws ModbusException { - checkTransaction(); - if (readInputDiscretesRequest == null) { - readInputDiscretesRequest = new ReadInputDiscretesRequest(); - } - readInputDiscretesRequest.setUnitID(unitId); - readInputDiscretesRequest.setReference(ref); - readInputDiscretesRequest.setBitCount(count); - transaction.setRequest(readInputDiscretesRequest); - transaction.execute(); - BitVector bv = ((ReadInputDiscretesResponse)getAndCheckResponse()).getDiscretes(); - bv.forceSize(count); - return bv; - } - - /** - * Reads a given number of input registers from the slave. - * - * Note that the number of input registers returned (i.e. array length) - * will be according to the number received in the slave response. - * - * @param unitId the slave unit id. - * @param ref the offset of the input register to start reading from. - * @param count the number of input registers to be read. - * - * @return a InputRegister[] with the received input registers. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized InputRegister[] readInputRegisters(int unitId, int ref, int count) throws ModbusException { - checkTransaction(); - if (readInputRegistersRequest == null) { - readInputRegistersRequest = new ReadInputRegistersRequest(); - } - readInputRegistersRequest.setUnitID(unitId); - readInputRegistersRequest.setReference(ref); - readInputRegistersRequest.setWordCount(count); - transaction.setRequest(readInputRegistersRequest); - transaction.execute(); - return ((ReadInputRegistersResponse) getAndCheckResponse()).getRegisters(); - } - - /** - * Reads a given number of registers from the slave. - * - * Note that the number of registers returned (i.e. array length) - * will be according to the number received in the slave response. - * - * @param unitId the slave unit id. - * @param ref the offset of the register to start reading from. - * @param count the number of registers to be read. - * - * @return a Register[] holding the received registers. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized Register[] readMultipleRegisters(int unitId, int ref, int count) throws ModbusException { - checkTransaction(); - if (readMultipleRegistersRequest == null) { - readMultipleRegistersRequest = new ReadMultipleRegistersRequest(); - } - readMultipleRegistersRequest.setUnitID(unitId); - readMultipleRegistersRequest.setReference(ref); - readMultipleRegistersRequest.setWordCount(count); - transaction.setRequest(readMultipleRegistersRequest); - transaction.execute(); - return ((ReadMultipleRegistersResponse) getAndCheckResponse()).getRegisters(); - } - - /** - * Writes a single register to the slave. - * - * @param unitId the slave unit id. - * @param ref the offset of the register to be written. - * @param register a Register holding the value of the register - * to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeSingleRegister(int unitId, int ref, Register register) throws ModbusException { - checkTransaction(); - if (writeSingleRegisterRequest == null) { - writeSingleRegisterRequest = new WriteSingleRegisterRequest(); - } - writeSingleRegisterRequest.setUnitID(unitId); - writeSingleRegisterRequest.setReference(ref); - writeSingleRegisterRequest.setRegister(register); - transaction.setRequest(writeSingleRegisterRequest); - transaction.execute(); - } - - /** - * Writes a number of registers to the slave. - * - * @param unitId the slave unit id. - * @param ref the offset of the register to start writing to. - * @param registers a Register[] holding the values of - * the registers to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeMultipleRegisters(int unitId, int ref, Register[] registers) throws ModbusException { - checkTransaction(); - if (writeMultipleRegistersRequest == null) { - writeMultipleRegistersRequest = new WriteMultipleRegistersRequest(); - } - writeMultipleRegistersRequest.setUnitID(unitId); - writeMultipleRegistersRequest.setReference(ref); - writeMultipleRegistersRequest.setRegisters(registers); - transaction.setRequest(writeMultipleRegistersRequest); - transaction.execute(); - } - - /** - * Reads a given number of coil states from the slave. - * - * Note that the number of bits in the bit vector will be - * forced to the number originally requested. - * - * @param ref the offset of the coil to start reading from. - * @param count the number of coil states to be read. - * - * @return a BitVector instance holding the - * received coil states. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized BitVector readCoils(int ref, int count) throws ModbusException { - return readCoils(DEFAULT_UNIT_ID, ref, count); - } - - /** - * Writes a coil state to the slave. - * - * @param ref the offset of the coil to be written. - * @param state the coil state to be written. - * - * @return the state of the coil as returned from the slave. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized boolean writeCoil(int ref, boolean state) throws ModbusException { - return writeCoil(DEFAULT_UNIT_ID, ref, state); - } - - /** - * Writes a given number of coil states to the slave. - * - * Note that the number of coils to be written is given - * implicitly, through {@link BitVector#size()}. - * - * @param ref the offset of the coil to start writing to. - * @param coils a BitVector which holds the coil states to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeMultipleCoils(int ref, BitVector coils) throws ModbusException { - writeMultipleCoils(DEFAULT_UNIT_ID, ref, coils); - } - - /** - * Reads a given number of input discrete states from the slave. - * - * Note that the number of bits in the bit vector will be - * forced to the number originally requested. - * - * @param ref the offset of the input discrete to start reading from. - * @param count the number of input discrete states to be read. - * - * @return a BitVector instance holding the received input discrete - * states. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized BitVector readInputDiscretes(int ref, int count) throws ModbusException { - return readInputDiscretes(DEFAULT_UNIT_ID, ref, count); - } - - /** - * Reads a given number of input registers from the slave. - * - * Note that the number of input registers returned (i.e. array length) - * will be according to the number received in the slave response. - * - * @param ref the offset of the input register to start reading from. - * @param count the number of input registers to be read. - * - * @return a InputRegister[] with the received input registers. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized InputRegister[] readInputRegisters(int ref, int count) throws ModbusException { - return readInputRegisters(DEFAULT_UNIT_ID, ref, count); - } - - /** - * Reads a given number of registers from the slave. - * - * Note that the number of registers returned (i.e. array length) - * will be according to the number received in the slave response. - * - * @param ref the offset of the register to start reading from. - * @param count the number of registers to be read. - * - * @return a Register[] holding the received registers. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized Register[] readMultipleRegisters(int ref, int count) throws ModbusException { - return readMultipleRegisters(DEFAULT_UNIT_ID, ref, count); - } - - /** - * Writes a single register to the slave. - * - * @param ref the offset of the register to be written. - * @param register a Register holding the value of the register - * to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeSingleRegister(int ref, Register register) throws ModbusException { - writeSingleRegister(DEFAULT_UNIT_ID, ref, register); - } - - /** - * Writes a number of registers to the slave. - * - * @param ref the offset of the register to start writing to. - * @param registers a Register[] holding the values of - * the registers to be written. - * - * @throws ModbusException if an I/O error, a slave exception or - * a transaction error occurs. - */ - public synchronized void writeMultipleRegisters(int ref, Register[] registers) throws ModbusException { - writeMultipleRegisters(DEFAULT_UNIT_ID, ref, registers); - } - - /** - * Reads the response from the transaction - * If there is no response, then it throws an error - * - * @return Modbus response - * - * @throws ModbusException If response is null - */ - private ModbusResponse getAndCheckResponse() throws ModbusException { - ModbusResponse res = transaction.getResponse(); - if (res == null) { - throw new ModbusException("No response"); - } - return res; - } - - /** - * Checks to make sure there is a transaction to use - * - * @throws ModbusException If transaction is null - */ - private void checkTransaction() throws ModbusException { - if (transaction == null) { - throw new ModbusException("No transaction created, probably not connected"); - } - } - - /** - * Returns the receive timeout in milliseconds - * - * @return Timeout in milliseconds - */ - public int getTimeout() { - return timeout; - } - - /** - * Sets the receive timeout - * - * @param timeout Timeout in milliseconds - */ - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - /** - * Set the amount of retries for opening - * the connection for executing the transaction. - * - * @param retries the amount of retries as int. - */ - synchronized public void setRetries(int retries) { - if (transaction != null) { - transaction.setRetries(retries); - } - } - - /** - * Sets the flag that controls whether the - * validity of a transaction will be checked. - * - * @param b true if checking validity, false otherwise. - */ - synchronized public void setCheckingValidity(boolean b) { - if (transaction != null) { - transaction.setCheckingValidity(b); - } - } - - /** - * Returns the transport being used by the - * - * @return ModbusTransport - */ - public abstract AbstractModbusTransport getTransport(); - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java b/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java deleted file mode 100644 index b39ac86..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.facade; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction; -import com.ghgande.j2mod.modbus.net.TCPMasterConnection; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Modbus/TCP Master facade. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusTCPMaster extends AbstractModbusMaster { - - private TCPMasterConnection connection; - private boolean reconnecting = false; - private boolean useRtuOverTcp = false; - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - */ - public ModbusTCPMaster(String addr) { - this(addr, Modbus.DEFAULT_PORT, Modbus.DEFAULT_TIMEOUT, false, false); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public ModbusTCPMaster(String addr, boolean useRtuOverTcp) { - this(addr, Modbus.DEFAULT_PORT, Modbus.DEFAULT_TIMEOUT, false, useRtuOverTcp); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - */ - public ModbusTCPMaster(String addr, int port) { - this(addr, port, Modbus.DEFAULT_TIMEOUT, false, false); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public ModbusTCPMaster(String addr, int port, boolean useRtuOverTcp) { - this(addr, port, Modbus.DEFAULT_TIMEOUT, false, useRtuOverTcp); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - * @param timeout Socket timeout in milliseconds - * @param reconnect True if the socket should reconnect if it detects a connection failure - */ - public ModbusTCPMaster(String addr, int port, int timeout, boolean reconnect) { - this(addr, port, timeout, reconnect, false); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - * @param timeout Socket timeout in milliseconds - * @param reconnect True if the socket should reconnect if it detcts a connection failure - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public ModbusTCPMaster(String addr, int port, int timeout, boolean reconnect, boolean useRtuOverTcp) { - super(); - this.useRtuOverTcp = useRtuOverTcp; - try { - InetAddress slaveAddress = InetAddress.getByName(addr); - connection = new TCPMasterConnection(slaveAddress); - connection.setPort(port); - connection.setTimeout(timeout); - this.timeout = timeout; - setReconnecting(reconnect); - } - catch (UnknownHostException e) { - throw new RuntimeException("Failed to contruct ModbusTCPMaster instance.", e); - } - } - - /** - * Connects this ModbusTCPMaster with the slave. - * - * @throws Exception if the connection cannot be established. - */ - public synchronized void connect() throws Exception { - if (connection != null && !connection.isConnected()) { - connection.connect(useRtuOverTcp); - transaction = connection.getModbusTransport().createTransaction(); - ((ModbusTCPTransaction)transaction).setReconnecting(reconnecting); - setTransaction(transaction); - } - } - - /** - * Disconnects this ModbusTCPMaster from the slave. - */ - public synchronized void disconnect() { - if (connection != null && connection.isConnected()) { - connection.close(); - transaction = null; - setTransaction(null); - } - } - - /** - * Tests if a constant connection is maintained or if a new - * connection is established for every transaction. - * - * @return true if a new connection should be established for each - * transaction, false otherwise. - */ - public boolean isReconnecting() { - return reconnecting; - } - - /** - * Sets the flag that specifies whether to maintain a - * constant connection or reconnect for every transaction. - * - * @param b true if a new connection should be established for each - * transaction, false otherwise. - */ - public synchronized void setReconnecting(boolean b) { - reconnecting = b; - if (transaction != null) { - ((ModbusTCPTransaction)transaction).setReconnecting(b); - } - } - - @Override - public void setTimeout(int timeout) { - super.setTimeout(timeout); - if (connection != null) { - connection.setTimeout(timeout); - } - } - - @Override - public AbstractModbusTransport getTransport() { - return connection == null ? null : connection.getModbusTransport(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusUDPMaster.java b/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusUDPMaster.java deleted file mode 100644 index 793783e..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusUDPMaster.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.facade; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.net.UDPMasterConnection; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Modbus/UDP Master facade. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusUDPMaster extends AbstractModbusMaster { - - private static final Logger logger = LoggerFactory.getLogger(ModbusUDPMaster.class); - - private UDPMasterConnection connection; - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - */ - public ModbusUDPMaster(String addr) { - this(addr, Modbus.DEFAULT_PORT); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - */ - public ModbusUDPMaster(String addr, int port) { - this(addr, port, Modbus.DEFAULT_TIMEOUT); - } - - /** - * Constructs a new master facade instance for communication - * with a given slave. - * - * @param addr an internet address as resolvable IP name or IP number, - * specifying the slave to communicate with. - * @param port the port the slave is listening to. - * @param timeout Socket timeout in milliseconds - */ - public ModbusUDPMaster(String addr, int port, int timeout) { - super(); - try { - InetAddress slaveAddress = InetAddress.getByName(addr); - connection = new UDPMasterConnection(slaveAddress); - connection.setPort(port); - connection.setTimeout(timeout); - } - catch (UnknownHostException e) { - throw new RuntimeException("Failed to construct ModbusUDPMaster instance.", e); - } - } - - /** - * Connects this ModbusTCPMaster with the slave. - * - * @throws Exception if the connection cannot be established. - */ - public synchronized void connect() throws Exception { - if (connection != null && !connection.isConnected()) { - connection.connect(); - transaction = connection.getModbusTransport().createTransaction(); - setTransaction(transaction); - } - } - - /** - * Disconnects this ModbusTCPMaster from the slave. - */ - public synchronized void disconnect() { - if (connection != null && connection.isConnected()) { - connection.close(); - transaction = null; - setTransaction(null); - } - } - - @Override - public void setTimeout(int timeout) { - super.setTimeout(timeout); - if (connection != null) { - connection.setTimeout(timeout); - } - } - - @Override - public AbstractModbusTransport getTransport() { - return connection == null ? null : connection.getModbusTransport(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractModbusTransport.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractModbusTransport.java deleted file mode 100644 index 2bc9408..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractModbusTransport.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.IOException; - -/** - * Interface defining the I/O mechanisms for - * ModbusMessage instances. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class AbstractModbusTransport { - - protected int timeout = Modbus.DEFAULT_TIMEOUT; - - /** - * Set the socket timeout - * - * @param time Timeout in milliseconds - */ - public void setTimeout(int time) { - timeout = time; - } - - /** - * Closes the raw input and output streams of - * this ModbusTransport. - *

- * - * @throws IOException if a stream - * cannot be closed properly. - */ - public abstract void close() throws IOException; - - /** - * Creates a Modbus transaction for the underlying transport. - * - * @return the new transaction - */ - public abstract ModbusTransaction createTransaction(); - - /** - * Writes a ModbusMessage to the - * output stream of this ModbusTransport. - *

- * - * @param msg a ModbusMessage. - * - * @throws ModbusIOException data cannot be - * written properly to the raw output stream of - * this ModbusTransport. - */ - public abstract void writeRequest(ModbusRequest msg) throws ModbusIOException; - - /** - * Writes a ModbusResponseMessage to the - * output stream of this ModbusTransport. - *

- * - * @param msg a ModbusMessage. - * - * @throws ModbusIOException data cannot be - * written properly to the raw output stream of - * this ModbusTransport. - */ - public abstract void writeResponse(ModbusResponse msg) throws ModbusIOException; - - /** - * Reads a ModbusRequest from the - * input stream of this ModbusTransport. - *

- * - * @param listener Listener the request was received by - * - * @return req the ModbusRequest read from the underlying stream. - * - * @throws ModbusIOException data cannot be - * read properly from the raw input stream of - * this ModbusTransport. - */ - public abstract ModbusRequest readRequest(AbstractModbusListener listener) throws ModbusIOException; - - /** - * Reads a ModbusResponse from the - * input stream of this ModbusTransport. - *

- * - * @return res the ModbusResponse read from the underlying stream. - * - * @throws ModbusIOException data cannot be - * read properly from the raw input stream of - * this ModbusTransport. - */ - public abstract ModbusResponse readResponse() throws ModbusIOException; - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractSerialTransportListener.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractSerialTransportListener.java deleted file mode 100644 index cf1b44d..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/AbstractSerialTransportListener.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.msg.ModbusMessage; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; -import com.ghgande.j2mod.modbus.net.AbstractSerialConnection; - -/** - * Any class that wants to listen for the begining and ending of read/writes - * to the Serial channel need to implement this interface - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -abstract public class AbstractSerialTransportListener { - - /** - * Will be called whenever a message is about to be written - * - * @param port Port being used - * @param msg Message to be written - */ - public void beforeMessageWrite(AbstractSerialConnection port, ModbusMessage msg) { - } - - /** - * Will be called whenever a message has been written - * - * @param port Port being used - * @param msg Message written - */ - public void afterMessageWrite(AbstractSerialConnection port, ModbusMessage msg) { - } - - /** - * Called before a request is read - * - * @param port Port to read - */ - public void beforeRequestRead(AbstractSerialConnection port) { - } - - /** - * Called whenever a request has been received - * - * @param port Port to read - * @param req Request received - */ - public void afterRequestRead(AbstractSerialConnection port, ModbusRequest req) { - } - - /** - * Called before a response is read - * - * @param port Port to read - */ - public void beforeResponseRead(AbstractSerialConnection port) { - } - - /** - * Called whenever a response has been received - * - * @param port Port to read - * @param res Response received - */ - public void afterResponseRead(AbstractSerialConnection port, ModbusResponse res) { - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesInputStream.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesInputStream.java deleted file mode 100644 index 9332178..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesInputStream.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.IOException; - -/** - * Class implementing a byte array input stream with - * a DataInput interface. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class BytesInputStream - extends FastByteArrayInputStream implements DataInput { - - DataInputStream dataInputStream; - - /** - * Constructs a new BytesInputStream instance, - * with an empty buffer of a given size. - * - * @param size the size of the input buffer. - */ - public BytesInputStream(int size) { - super(new byte[size]); - dataInputStream = new DataInputStream(this); - } - - /** - * Constructs a new BytesInputStream instance, - * that will read from the given data. - * - * @param data a byte array containing data to be read. - */ - public BytesInputStream(byte[] data) { - super(data); - dataInputStream = new DataInputStream(this); - } - - /** - * Resets this BytesInputStream using the given - * byte[] as new input buffer. - * - * @param data a byte array with data to be read. - */ - public void reset(byte[] data) { - pos = 0; - mark = 0; - buf = data; - count = data.length; - } - - /** - * Resets this BytesInputStream using the given - * byte[] as new input buffer and a given length. - * - * @param data a byte array with data to be read. - * @param length the length of the buffer to be considered. - */ - public void reset(byte[] data, int length) { - pos = 0; - mark = 0; - count = length; - buf = data; - } - - /** - * Resets this BytesInputStream assigning the input buffer - * a new length. - * - * @param length the length of the buffer to be considered. - */ - public void reset(int length) { - pos = 0; - count = length; - } - - /** - * Skips the given number of bytes or all bytes till the end - * of the assigned input buffer length. - * - * @param n the number of bytes to be skipped as int. - * - * @return the number of bytes skipped. - */ - public int skip(int n) { - mark(pos); - pos += n; - return n; - } - - /** - * Returns the reference to the input buffer. - * - * @return the reference to the byte[] input buffer. - */ - public synchronized byte[] getBuffer() { - byte[] dest = new byte[buf.length]; - System.arraycopy(buf, 0, dest, 0, dest.length); - return dest; - } - - public int getBufferLength() { - return buf.length; - } - - public void readFully(byte b[]) throws IOException { - dataInputStream.readFully(b); - } - - public void readFully(byte b[], int off, int len) throws IOException { - dataInputStream.readFully(b, off, len); - } - - public int skipBytes(int n) throws IOException { - return dataInputStream.skipBytes(n); - } - - public boolean readBoolean() throws IOException { - return dataInputStream.readBoolean(); - } - - public byte readByte() throws IOException { - return dataInputStream.readByte(); - } - - public int readUnsignedByte() throws IOException { - return dataInputStream.readUnsignedByte(); - } - - public short readShort() throws IOException { - return dataInputStream.readShort(); - } - - public int readUnsignedShort() throws IOException { - return dataInputStream.readUnsignedShort(); - } - - public char readChar() throws IOException { - return dataInputStream.readChar(); - } - - public int readInt() throws IOException { - return dataInputStream.readInt(); - } - - public long readLong() throws IOException { - return dataInputStream.readLong(); - } - - public float readFloat() throws IOException { - return dataInputStream.readFloat(); - } - - public double readDouble() throws IOException { - return dataInputStream.readDouble(); - } - - public String readLine() throws IOException { - throw new IOException("Not supported"); - } - - public String readUTF() throws IOException { - return dataInputStream.readUTF(); - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesOutputStream.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesOutputStream.java deleted file mode 100644 index 976f1ba..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/BytesOutputStream.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.IOException; - -/** - * Class implementing a byte array output stream with - * a DataInput interface. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class BytesOutputStream extends FastByteArrayOutputStream implements DataOutput { - - private DataOutputStream dataOutputStream; - - /** - * Constructs a new BytesOutputStream instance with - * a new output buffer of the given size. - * - * @param size the size of the output buffer as int. - */ - public BytesOutputStream(int size) { - super(size); - dataOutputStream = new DataOutputStream(this); - } - - /** - * Constructs a new BytesOutputStream instance with - * a given output buffer. - * - * @param buffer the output buffer as byte[]. - */ - public BytesOutputStream(byte[] buffer) { - buf = buffer; - count = 0; - dataOutputStream = new DataOutputStream(this); - } - - /** - * Returns the reference to the output buffer. - * - * @return the reference to the byte[] output buffer. - */ - public synchronized byte[] getBuffer() { - byte[] dest = new byte[buf.length]; - System.arraycopy(buf, 0, dest, 0, dest.length); - return dest; - } - - public void reset() { - count = 0; - } - - public void writeBoolean(boolean v) throws IOException { - dataOutputStream.writeBoolean(v); - } - - public void writeByte(int v) throws IOException { - dataOutputStream.writeByte(v); - } - - public void writeShort(int v) throws IOException { - dataOutputStream.writeShort(v); - } - - public void writeChar(int v) throws IOException { - dataOutputStream.writeChar(v); - } - - public void writeInt(int v) throws IOException { - dataOutputStream.writeInt(v); - } - - public void writeLong(long v) throws IOException { - dataOutputStream.writeLong(v); - } - - public void writeFloat(float v) throws IOException { - dataOutputStream.writeFloat(v); - } - - public void writeDouble(double v) throws IOException { - dataOutputStream.writeDouble(v); - } - - public void writeBytes(String s) throws IOException { - int len = s.length(); - for (int i = 0; i < len; i++) { - this.write((byte)s.charAt(i)); - } - } - - public void writeChars(String s) throws IOException { - dataOutputStream.writeChars(s); - } - - public void writeUTF(String str) throws IOException { - dataOutputStream.writeUTF(str); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayInputStream.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayInputStream.java deleted file mode 100644 index 65b1636..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayInputStream.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This class is a replacement for ByteArrayInputStream that does not - * synchronize every byte read. - * - * @author Mark Hayes - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class FastByteArrayInputStream extends InputStream { - - private static final Logger logger = LoggerFactory.getLogger(FastByteArrayInputStream.class); - - /** - * Number of bytes in the input buffer. - */ - protected int count; - - /** - * Actual position pointer into the input buffer. - */ - int pos; - - /** - * Marked position pointer into the input buffer. - */ - int mark; - /** - * Input buffer byte[]. - */ - byte[] buf; - - /** - * Creates an input stream. - * - * @param buffer the data to read. - */ - FastByteArrayInputStream(byte[] buffer) { - buf = buffer; - count = buffer.length; - pos = 0; - mark = 0; - } - - // --- begin ByteArrayInputStream compatible methods --- - - public int read() throws IOException { - logger.debug("read()"); - logger.debug("count={} pos={}", count, pos); - return (pos < count) ? (buf[pos++] & 0xff) : (-1); - } - - public int read(byte[] toBuf) throws IOException { - logger.debug("read(byte[])"); - return read(toBuf, 0, toBuf.length); - } - - public int read(byte[] toBuf, int offset, int length) throws IOException { - logger.debug("read(byte[],int,int)"); - int avail = count - pos; - if (avail <= 0) { - return -1; - } - if (length > avail) { - length = avail; - } - for (int i = 0; i < length; i++) { - toBuf[offset++] = buf[pos++]; - } - return length; - } - - public long skip(long count) { - int myCount = (int)count; - if (myCount + pos > this.count) { - myCount = this.count - pos; - } - pos += myCount; - return myCount; - } - - public int available() { - return count - pos; - } - - public int getCount() { - return count; - } - - public void mark(int readlimit) { - logger.debug("mark()"); - mark = pos; - logger.debug("mark={} pos={}", mark, pos); - } - - public void reset() { - logger.debug("reset()"); - pos = mark; - logger.debug("mark={} pos={}", mark, pos); - } - - public boolean markSupported() { - return true; - } - - // --- end ByteArrayInputStream compatible methods --- - - public byte[] toByteArray() { - byte[] toBuf = new byte[count]; - System.arraycopy(buf, 0, toBuf, 0, count); - return toBuf; - } - - /** - * Returns the underlying data being read. - * - * @return the underlying data. - */ - public synchronized byte[] getBufferBytes() { - byte[] dest = new byte[count]; - System.arraycopy(buf, 0, dest, 0, dest.length); - return dest; - } - - /** - * Returns the offset at which data is being read from the buffer. - * - * @return the offset at which data is being read. - */ - public int getBufferOffset() { - return pos; - } - - /** - * Returns the end of the buffer being read. - * - * @return the end of the buffer. - */ - public int getBufferLength() { - return count; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayOutputStream.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayOutputStream.java deleted file mode 100644 index be3a0c5..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/FastByteArrayOutputStream.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -/** - * This class is a replacement implementation for ByteArrayOutputStream - * that does not synchronize every - * byte written. - * - * @author Mark Hayes - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class FastByteArrayOutputStream extends OutputStream { - - private static final Logger logger = LoggerFactory.getLogger(FastByteArrayOutputStream.class); - - /** - * Defines the default oputput buffer size (100 bytes). - */ - private static final int DEFAULT_INIT_SIZE = 100; - /** - * Defines the default increment of the output buffer size - * (100 bytes). - */ - private static final int DEFAULT_BUMP_SIZE = 100; - - /** - * Number of bytes in the output buffer. - */ - protected int count; - - /** - * Increment of the output buffer size on overflow. - */ - private int bumpLen; - - /** - * Output buffer byte[]. - */ - byte[] buf; - - /** - * Creates an output stream with default sizes. - */ - FastByteArrayOutputStream() { - buf = new byte[DEFAULT_INIT_SIZE]; - bumpLen = DEFAULT_BUMP_SIZE; - } - - /** - * Creates an output stream with a default bump size and a given initial - * size. - * - * @param initialSize the initial size of the buffer. - */ - FastByteArrayOutputStream(int initialSize) { - buf = new byte[initialSize]; - bumpLen = DEFAULT_BUMP_SIZE; - } - - /** - * Creates an output stream with a given bump size and initial size. - * - * @param initialSize the initial size of the buffer. - * @param bumpSize the amount to increment the buffer. - */ - public FastByteArrayOutputStream(int initialSize, int bumpSize) { - buf = new byte[initialSize]; - bumpLen = bumpSize; - } - - // --- begin ByteArrayOutputStream compatible methods --- - - /** - * Returns the number of bytes written to this - * FastByteArrayOutputStream. - * - * @return the number of bytes written as int. - */ - public int size() { - return count; - } - - /** - * Resets this FastByteArrayOutputStream. - */ - public void reset() { - count = 0; - } - - public void write(int b) throws IOException { - if (count + 1 > buf.length) { - bump(1); - } - buf[count++] = (byte)b; - } - - public void write(byte[] fromBuf) throws IOException { - int needed = count + fromBuf.length - buf.length; - if (needed > 0) { - bump(needed); - } - for (byte aFromBuf : fromBuf) { - buf[count++] = aFromBuf; - } - } - - public void write(byte[] fromBuf, int offset, int length) throws IOException { - - int needed = count + length - buf.length; - if (needed > 0) { - bump(needed); - } - int fromLen = offset + length; - - for (int i = offset; i < fromLen; i++) { - buf[count++] = fromBuf[i]; - } - } - - /** - * Writes the content of this FastByteArrayOutputStream - * to the given output stream. - * - * @param out the output stream to be written to. - * - * @throws IOException if an I/O error occurs. - */ - public synchronized void writeTo(OutputStream out) throws IOException { - out.write(buf, 0, count); - } - - public String toString() { - try { - return new String(buf, 0, count, "US-ASCII"); - } - catch (Exception e) { - logger.debug("Problem converting bytes to string - {}", e.getMessage()); - } - return ""; - } - - /** - * Returns the content of this FastByteArrayOutputStream - * as String. - * - * @param encoding the encoding to be used for conversion. - * - * @return a newly allocated String. - * - * @throws UnsupportedEncodingException if the given encoding is not supported. - */ - public String toString(String encoding) throws UnsupportedEncodingException { - return new String(buf, 0, count, encoding); - } - - /** - * Returns the written bytes in a newly allocated byte[] - * of length getSize(). - * - * @return a newly allocated byte[] with the content of the - * output buffer. - */ - public byte[] toByteArray() { - byte[] toBuf = new byte[count]; - System.arraycopy(buf, 0, toBuf, 0, count); - //for (int i = 0; i < count; i++) { - // toBuf[i] = buf[i]; - //} - return toBuf; - } - - // --- end ByteArrayOutputStream compatible methods --- - - /** - * Copy the buffered data to the given array. - * - * @param toBuf the buffer to hold a copy of the data. - * @param offset the offset at which to start copying. - */ - public void toByteArray(byte[] toBuf, int offset) { - int toLen = (toBuf.length > count) ? count : toBuf.length; - System.arraycopy(buf, offset, toBuf, offset, toLen - offset); - } - - /** - * Returns the buffer owned by this object. - * - * @return the buffer. - */ - public synchronized byte[] getBufferBytes() { - byte[] dest = new byte[count]; - System.arraycopy(buf, 0, dest, 0, dest.length); - return dest; - } - - /** - * Returns the offset of the internal buffer. - * - * @return always zero currently. - */ - public int getBufferOffset() { - return 0; - } - - /** - * Returns the length used in the internal buffer, that is, the offset at - * which data will be written next. - * - * @return the buffer length. - */ - public int getBufferLength() { - return count; - } - - /** - * Ensure that at least the given number of bytes are available in the - * internal buffer. - * - * @param sizeNeeded the number of bytes desired. - */ - public void makeSpace(int sizeNeeded) { - int needed = count + sizeNeeded - buf.length; - if (needed > 0) { - bump(needed); - } - } - - /** - * Skip the given number of bytes in the buffer. - * - * @param sizeAdded number of bytes to skip. - */ - public void addSize(int sizeAdded) { - count += sizeAdded; - } - - private void bump(int needed) { - - byte[] toBuf = new byte[buf.length + needed + bumpLen]; - - System.arraycopy(buf, 0, toBuf, 0, count); - buf = toBuf; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusRTUTCPTransport.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusRTUTCPTransport.java deleted file mode 100644 index fd4349d..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusRTUTCPTransport.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; - -import java.net.Socket; - -/** - * Class that implements the ModbusRTU over tCP transport flavor. - * - * @author axuan - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusRTUTCPTransport extends ModbusTCPTransport { - - /** - * Default constructor - */ - public ModbusRTUTCPTransport() { - // RTU over TCP is headless by default - setHeadless(); - } - - /** - * Constructs a new ModbusTransport instance, for a given - * Socket. - *

- * - * @param socket the Socket used for message transport. - */ - public ModbusRTUTCPTransport(Socket socket) { - super(socket); - // RTU over TCP is headless by default - setHeadless(); - } - - @Override - public void writeResponse(ModbusResponse msg) throws ModbusIOException { - writeMessage(msg, true); - } - - @Override - public void writeRequest(ModbusRequest msg) throws ModbusIOException { - writeMessage(msg, true); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransaction.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransaction.java deleted file mode 100644 index f112c04..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransaction.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.ModbusSlaveException; -import com.ghgande.j2mod.modbus.msg.ExceptionResponse; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.net.TCPMasterConnection; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class implementing the ModbusTransaction interface. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusTCPTransaction extends ModbusTransaction { - - private static final Logger logger = LoggerFactory.getLogger(ModbusTCPTransaction.class); - - // instance attributes and associations - private TCPMasterConnection connection; - protected boolean reconnecting = Modbus.DEFAULT_RECONNECTING; - - /** - * Constructs a new ModbusTCPTransaction instance. - */ - public ModbusTCPTransaction() { - } - - /** - * Constructs a new ModbusTCPTransaction instance with a given - * ModbusRequest to be send when the transaction is executed. - *

- * - * @param request a ModbusRequest instance. - */ - public ModbusTCPTransaction(ModbusRequest request) { - setRequest(request); - } - - /** - * Constructs a new ModbusTCPTransaction instance with a given - * TCPMasterConnection to be used for transactions. - *

- * - * @param con a TCPMasterConnection instance. - */ - public ModbusTCPTransaction(TCPMasterConnection con) { - setConnection(con); - transport = con.getModbusTransport(); - } - - /** - * Sets the connection on which this ModbusTransaction should be - * executed. - *

- * An implementation should be able to handle open and closed connections. - *
- *

- * - * @param con a TCPMasterConnection. - */ - public synchronized void setConnection(TCPMasterConnection con) { - connection = con; - transport = con.getModbusTransport(); - } - - /** - * Tests if the connection will be opened and closed for each - * execution. - *

- * - * @return true if reconnecting, false otherwise. - */ - public boolean isReconnecting() { - return reconnecting; - } - - /** - * Sets the flag that controls whether a connection is opened and closed - * for each execution or not. - *

- * - * @param b true if reconnecting, false otherwise. - */ - public void setReconnecting(boolean b) { - reconnecting = b; - } - - @Override - public synchronized void execute() throws ModbusException { - - if (request == null || connection == null) { - throw new ModbusException("Invalid request or connection"); - } - - // Try sending the message up to retries time. Note that the message - // is read immediately after being written, with no flushing of buffers. - int retryCounter = 0; - int retryLimit = (retries > 0 ? retries : Modbus.DEFAULT_RETRIES); - boolean keepTrying = true; - - // While we haven't exhausted all the retry attempts - while (keepTrying) { - - // Automatically connect if we aren't already connected - if (!connection.isConnected()) { - try { - logger.debug("Connecting to: {}:{}", connection.getAddress().toString(), connection.getPort()); - connection.connect(); - transport = connection.getModbusTransport(); - } - catch (Exception ex) { - throw new ModbusIOException("Connection failed for %s:%d", connection.getAddress().toString(), connection.getPort(), ex.getMessage()); - } - } - - // Make sure the timeout is set - transport.setTimeout(connection.getTimeout()); - - try { - - // Write the message to the endpoint - logger.debug("Writing request: {} (try: {}) request transaction ID = {} to {}:{}", request.getHexMessage(), retryCounter, request.getTransactionID(), connection.getAddress().toString(), connection.getPort()); - transport.writeRequest(request); - - // Read the response - response = transport.readResponse(); - logger.debug("Read response: {} (try: {}) response transaction ID = {} from {}:{}", response.getHexMessage(), retryCounter, response.getTransactionID(), connection.getAddress().toString(), connection.getPort()); - keepTrying = false; - - // The slave may have returned an exception -- check for that. - if (response instanceof ExceptionResponse) { - throw new ModbusSlaveException(((ExceptionResponse)response).getExceptionCode()); - } - - // We need to keep retrying if; - // a) the response is empty OR - // b) we have been told to check the validity and the request/response transaction IDs don't match AND - // c) we haven't exceeded the maximum retry count - if (responseIsInValid()) { - retryCounter++; - if (retryCounter >= retryLimit) { - throw new ModbusIOException("Executing transaction failed (tried %d times)", retryLimit); - } - keepTrying = true; - long sleepTime = getRandomSleepTime(retryCounter); - if (response == null) { - logger.debug("Failed to get any response (try: {}) - retrying after {} milliseconds", retryCounter, sleepTime); - } - else { - logger.debug("Failed to get a valid response, transaction IDs do not match (try: {}) - retrying after {} milliseconds", retryCounter, sleepTime); - } - ModbusUtil.sleep(sleepTime); - } - } - catch (ModbusIOException ex) { - - // Up the retry counter and check if we are exhausted - retryCounter++; - if (retryCounter >= retryLimit) { - throw new ModbusIOException("Executing transaction %s failed (tried %d times) %s", request.getHexMessage(), retryLimit, ex.getMessage()); - } - else { - long sleepTime = getRandomSleepTime(retryCounter); - logger.debug("Failed transaction Request: {} (try: {}) - retrying after {} milliseconds", request.getHexMessage(), retryCounter, sleepTime); - ModbusUtil.sleep(sleepTime); - } - - // If this has happened, then we should close and re-open the connection before re-trying - logger.debug("Failed request {} (try: {}) request transaction ID = {} - {} closing and re-opening connection {}:{}", request.getHexMessage(), retryCounter, request.getTransactionID(), ex.getMessage(), connection.getAddress().toString(), connection.getPort()); - connection.close(); - } - - // Increment the transaction ID if we are still trying - if (keepTrying) { - incrementTransactionID(); - } - } - - // Close the connection if it isn't supposed to stick around. - if (isReconnecting()) { - connection.close(); - } - incrementTransactionID(); - } - - /** - * Returns true if the response is not valid - * This can be if the response is null or the transaction ID of the request - * doesn't match the reponse - * - * @return True if invalid - */ - private boolean responseIsInValid() { - if (response == null) { - return true; - } - else if (!response.isHeadless() && validityCheck) { - return request.getTransactionID() != response.getTransactionID(); - } - else { - return false; - } - } - - /** - * incrementTransactionID -- Increment the transaction ID for the next - * transaction. Note that the caller must get the new transaction ID with - * getTransactionID(). This is only done validity checking is enabled so - * that dumb slaves don't cause problems. The original request will have its - * transaction ID incremented as well so that sending the same transaction - * again won't cause problems. - */ - private synchronized void incrementTransactionID() { - if (isCheckingValidity()) { - if (transactionID >= Modbus.MAX_TRANSACTION_ID) { - transactionID = Modbus.DEFAULT_TRANSACTION_ID; - } - else { - transactionID++; - } - } - request.setTransactionID(getTransactionID()); - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransport.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransport.java deleted file mode 100644 index 0b6c56e..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTCPTransport.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.msg.ModbusMessage; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.net.TCPMasterConnection; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.*; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; - -/** - * Class that implements the Modbus transport flavor. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusTCPTransport extends AbstractModbusTransport { - - private static final Logger logger = LoggerFactory.getLogger(ModbusTCPTransport.class); - - // instance attributes - private DataInputStream dataInputStream; // input stream - private DataOutputStream dataOutputStream; // output stream - private final BytesInputStream byteInputStream = new BytesInputStream(Modbus.MAX_MESSAGE_LENGTH + 6); - private final BytesOutputStream byteOutputStream = new BytesOutputStream(Modbus.MAX_MESSAGE_LENGTH + 6); // write frames - protected Socket socket = null; - protected TCPMasterConnection master = null; - private boolean headless = false; // Some TCP implementations are. - - /** - * Default constructor - */ - public ModbusTCPTransport() { - } - - /** - * Constructs a new ModbusTransport instance, for a given - * Socket. - *

- * - * @param socket the Socket used for message transport. - */ - public ModbusTCPTransport(Socket socket) { - try { - setSocket(socket); - socket.setSoTimeout(timeout); - } - catch (IOException ex) { - logger.debug("ModbusTCPTransport::Socket invalid"); - - throw new IllegalStateException("Socket invalid", ex); - } - } - - /** - * Sets the Socket used for message transport and prepares the - * streams used for the actual I/O. - * - * @param socket the Socket used for message transport. - * - * @throws IOException if an I/O related error occurs. - */ - public void setSocket(Socket socket) throws IOException { - if (this.socket != null) { - this.socket.close(); - this.socket = null; - } - this.socket = socket; - setTimeout(timeout); - prepareStreams(socket); - } - - /** - * Set the transport to be headless - */ - public void setHeadless() { - headless = true; - } - - /** - * Set the transport to be headless - * - * @param headless True if headless - */ - public void setHeadless(boolean headless) { - this.headless = headless; - } - - /** - * Sets the master connection for the transport to use - * - * @param master Master - */ - public void setMaster(TCPMasterConnection master) { - this.master = master; - } - - @Override - public void setTimeout(int time) { - super.setTimeout(time); - if (socket != null) { - try { - socket.setSoTimeout(time); - } - catch (SocketException e) { - logger.warn("Socket exception occurred while setting timeout to " + time, e); - } - } - } - - @Override - public void close() throws IOException { - dataInputStream.close(); - dataOutputStream.close(); - socket.close(); - } - - @Override - public ModbusTransaction createTransaction() { - if (master == null) { - master = new TCPMasterConnection(socket.getInetAddress()); - master.setPort(socket.getPort()); - master.setModbusTransport(this); - } - return new ModbusTCPTransaction(master); - } - - @Override - public void writeResponse(ModbusResponse msg) throws ModbusIOException { - writeMessage(msg, false); - } - - @Override - public void writeRequest(ModbusRequest msg) throws ModbusIOException { - writeMessage(msg, false); - } - - @Override - public ModbusRequest readRequest(AbstractModbusListener listener) throws ModbusIOException { - ModbusRequest req; - try { - byteInputStream.reset(); - - synchronized (byteInputStream) { - byte[] buffer = byteInputStream.getBuffer(); - - if (!headless) { - dataInputStream.readFully(buffer, 0, 6); - - // The transaction ID must be treated as an unsigned short in - // order for validation to work correctly. - - int transaction = ModbusUtil.registerToShort(buffer, 0) & 0x0000FFFF; - int protocol = ModbusUtil.registerToShort(buffer, 2); - int count = ModbusUtil.registerToShort(buffer, 4); - - dataInputStream.readFully(buffer, 6, count); - - if (logger.isDebugEnabled()) { - logger.debug("Read: {}", ModbusUtil.toHex(buffer, 0, count + 6)); - } - - byteInputStream.reset(buffer, (6 + count)); - byteInputStream.skip(6); - - int unit = byteInputStream.readByte(); - int functionCode = byteInputStream.readUnsignedByte(); - - byteInputStream.reset(); - req = ModbusRequest.createModbusRequest(functionCode); - req.setUnitID(unit); - req.setHeadless(false); - - req.setTransactionID(transaction); - req.setProtocolID(protocol); - req.setDataLength(count); - - req.readFrom(byteInputStream); - } - else { - - // This is a headless request. - - int unit = dataInputStream.readByte(); - int function = dataInputStream.readByte(); - - req = ModbusRequest.createModbusRequest(function); - req.setUnitID(unit); - req.setHeadless(true); - req.readData(dataInputStream); - - // Discard the CRC. This is a TCP/IP connection, which has - // proper error correction and recovery. - - dataInputStream.readShort(); - if (logger.isDebugEnabled()) { - logger.debug("Read: {}", req.getHexMessage()); - } - } - } - return req; - } - catch (EOFException eoex) { - throw new ModbusIOException("End of File", true); - } - catch (SocketTimeoutException x) { - throw new ModbusIOException("Timeout reading request", x); - } - catch (SocketException sockex) { - throw new ModbusIOException("Socket Exception", sockex); - } - catch (IOException ex) { - throw new ModbusIOException("I/O exception - failed to read", ex); - } - } - - @Override - public ModbusResponse readResponse() throws ModbusIOException { - try { - ModbusResponse response; - - synchronized (byteInputStream) { - // use same buffer - byte[] buffer = byteInputStream.getBuffer(); - logger.debug("Reading response..."); - if (!headless) { - // All Modbus TCP transactions start with 6 bytes. Get them. - dataInputStream.readFully(buffer, 0, 6); - - /* - * The transaction ID is the first word (offset 0) in the - * data that was just read. It will be echoed back to the - * requester. - * - * The protocol ID is the second word (offset 2) in the - * data. It should always be 0, but I don't check. - * - * The length of the payload is the third word (offset 4) in - * the data that was just read. That's what I need in order - * to read the rest of the response. - */ - int transaction = ModbusUtil.registerToShort(buffer, 0) & 0x0000FFFF; - int protocol = ModbusUtil.registerToShort(buffer, 2); - int count = ModbusUtil.registerToShort(buffer, 4); - - dataInputStream.readFully(buffer, 6, count); - byteInputStream.reset(buffer, (6 + count)); - byteInputStream.reset(); - byteInputStream.skip(7); - int function = byteInputStream.readUnsignedByte(); - response = ModbusResponse.createModbusResponse(function); - - // Rewind the input buffer, then read the data into the - // response. - byteInputStream.reset(); - response.readFrom(byteInputStream); - - response.setTransactionID(transaction); - response.setProtocolID(protocol); - } - else { - // This is a headless response. It has the same format as a - // RTU over Serial response. - int unit = dataInputStream.readByte(); - int function = dataInputStream.readByte(); - - response = ModbusResponse.createModbusResponse(function); - response.setUnitID(unit); - response.setHeadless(); - response.readData(dataInputStream); - - // Now discard the CRC. Which hopefully wasn't needed - // because this is a TCP transport. - dataInputStream.readShort(); - } - } - if (logger.isDebugEnabled()) { - logger.debug("Successfully read: {}", response.getHexMessage()); - } - return response; - } - catch (EOFException ex1) { - throw new ModbusIOException("Premature end of stream (Message truncated) - %s", ex1.getMessage()); - } - catch (SocketTimeoutException ex2) { - throw new ModbusIOException("Socket timeout reading response - %s", ex2.getMessage()); - } - catch (Exception ex3) { - throw new ModbusIOException("General exception - failed to read - %s", ex3.getMessage()); - } - } - - /** - * Prepares the input and output streams of this ModbusTCPTransport - * instance based on the given socket. - * - * @param socket the socket used for communications. - * - * @throws IOException if an I/O related error occurs. - */ - private void prepareStreams(Socket socket) throws IOException { - - // Close any open streams if I'm being called because a new socket was - // set to handle this transport. - try { - if (dataInputStream != null) { - dataInputStream.close(); - } - if (dataOutputStream != null) { - dataOutputStream.close(); - } - } - catch (IOException x) { - // Do nothing. - } - - dataInputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream())); - dataOutputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); - } - - /** - * Writes a ModbusMessage to the - * output stream of this ModbusTransport. - *

- * - * @param msg a ModbusMessage. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * - * @throws ModbusIOException data cannot be - * written properly to the raw output stream of - * this ModbusTransport. - */ - void writeMessage(ModbusMessage msg, boolean useRtuOverTcp) throws ModbusIOException { - try { - if (logger.isDebugEnabled()) { - logger.debug("Sending: {}", msg.getHexMessage()); - } - byte message[] = msg.getMessage(); - - byteOutputStream.reset(); - if (!headless) { - byteOutputStream.writeShort(msg.getTransactionID()); - byteOutputStream.writeShort(msg.getProtocolID()); - byteOutputStream.writeShort((message != null ? message.length : 0) + 2); - } - byteOutputStream.writeByte(msg.getUnitID()); - byteOutputStream.writeByte(msg.getFunctionCode()); - if (message != null && message.length > 0) { - byteOutputStream.write(message); - } - - // Add CRC for RTU over TCP - if (useRtuOverTcp) { - int len = byteOutputStream.size(); - int[] crc = ModbusUtil.calculateCRC(byteOutputStream.getBuffer(), 0, len); - byteOutputStream.writeByte(crc[0]); - byteOutputStream.writeByte(crc[1]); - } - - dataOutputStream.write(byteOutputStream.toByteArray()); - dataOutputStream.flush(); - if (logger.isDebugEnabled()) { - logger.debug("Successfully sent: {}", ModbusUtil.toHex(byteOutputStream.toByteArray())); - } - // write more sophisticated exception handling - } - catch (SocketException ex1) { - if (master != null && !master.isConnected()) { - try { - master.connect(useRtuOverTcp); - } - catch (Exception e) { - // Do nothing. - } - } - throw new ModbusIOException("I/O socket exception - failed to write - %s", ex1.getMessage()); - } - catch (Exception ex2) { - throw new ModbusIOException("General exception - failed to write - %s", ex2.getMessage()); - } - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTransaction.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTransaction.java deleted file mode 100644 index 12c7a93..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusTransaction.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; - -import java.util.Random; - -/** - * Interface defining a ModbusTransaction. - *

- * A transaction is defined by the sequence of - * sending a request message and receiving a - * related response message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class ModbusTransaction { - - protected AbstractModbusTransport transport; - protected ModbusRequest request; - protected ModbusResponse response; - boolean validityCheck = Modbus.DEFAULT_VALIDITYCHECK; - int retries = Modbus.DEFAULT_RETRIES; - private Random random = new Random(System.nanoTime()); - static int transactionID = Modbus.DEFAULT_TRANSACTION_ID; - - /** - * Returns the ModbusRequest instance - * associated with this ModbusTransaction. - *

- * - * @return the associated ModbusRequest instance. - */ - public ModbusRequest getRequest() { - return request; - } - - /** - * Sets the ModbusRequest for this - * ModbusTransaction.

- * The related ModbusResponse is acquired - * from the passed in ModbusRequest instance.
- *

- * - * @param req a ModbusRequest. - */ - public void setRequest(ModbusRequest req) { - request = req; - if (req != null) { - request.setTransactionID(getTransactionID()); - } - } - - /** - * Returns the ModbusResponse instance - * associated with this ModbusTransaction. - *

- * - * @return the associated ModbusRequest instance. - */ - public ModbusResponse getResponse() { - return response; - } - - /** - * Returns the amount of retries for opening - * the connection for executing the transaction. - *

- * - * @return the amount of retries as int. - */ - int getRetries() { - return retries; - } - - /** - * Set the amount of retries for opening - * the connection for executing the transaction. - *

- * - * @param retries the amount of retries as int. - */ - public void setRetries(int retries) { - this.retries = retries; - } - - /** - * Tests whether the validity of a transaction - * will be checked. - *

- * - * @return true if checking validity, false otherwise. - */ - public boolean isCheckingValidity() { - return validityCheck; - } - - /** - * Sets the flag that controls whether the - * validity of a transaction will be checked. - *

- * - * @param b true if checking validity, false otherwise. - */ - public void setCheckingValidity(boolean b) { - validityCheck = b; - } - - /** - * getTransactionID -- get the next transaction ID to use. - * @return next transaction ID to use - */ - synchronized public int getTransactionID() { - /* - * Ensure that the transaction ID is in the valid range between - * 0 and MAX_TRANSACTION_ID (65534). If not, the value will be forced - * to 0. - */ - if (transactionID < Modbus.DEFAULT_TRANSACTION_ID && isCheckingValidity()) { - transactionID = Modbus.DEFAULT_TRANSACTION_ID; - } - if (transactionID >= Modbus.MAX_TRANSACTION_ID) { - transactionID = Modbus.DEFAULT_TRANSACTION_ID; - } - return transactionID; - } - - /** - * A useful method for getting a random sleep time based on an increment of the retry count and retry sleep time - * - * @param count Retry count - * @return Random sleep time in milliseconds - */ - long getRandomSleepTime(int count) { - return (Modbus.RETRY_SLEEP_TIME / 2) + (long) (random.nextDouble() * Modbus.RETRY_SLEEP_TIME * count); - } - - /** - * Executes this ModbusTransaction. - * Locks the ModbusTransport for sending - * the ModbusRequest and reading the - * related ModbusResponse. - * If reconnecting is activated the connection will - * be opened for the transaction and closed afterwards. - *

- * - * @throws ModbusException if an I/O error occurs, - * or the response is a modbus protocol exception. - */ - public abstract void execute() throws ModbusException; - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransaction.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransaction.java deleted file mode 100644 index 1ca212c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransaction.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.ModbusSlaveException; -import com.ghgande.j2mod.modbus.msg.ExceptionResponse; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.net.AbstractUDPTerminal; -import com.ghgande.j2mod.modbus.net.UDPMasterConnection; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class implementing the ModbusTransaction - * interface for the UDP transport mechanism. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusUDPTransaction extends ModbusTransaction { - - private static final Logger logger = LoggerFactory.getLogger(ModbusUDPTransaction.class); - - //instance attributes and associations - private AbstractUDPTerminal terminal; - private final Object MUTEX = new Object(); - - /** - * Constructs a new ModbusUDPTransaction - * instance. - */ - public ModbusUDPTransaction() { - } - - /** - * Constructs a new ModbusUDPTransaction - * instance with a given ModbusRequest to - * be send when the transaction is executed. - *

- * - * @param request a ModbusRequest instance. - */ - public ModbusUDPTransaction(ModbusRequest request) { - setRequest(request); - } - - /** - * Constructs a new ModbusUDPTransaction - * instance with a given UDPTerminal to - * be used for transactions. - *

- * - * @param terminal a UDPTerminal instance. - */ - public ModbusUDPTransaction(AbstractUDPTerminal terminal) { - setTerminal(terminal); - } - - /** - * Constructs a new ModbusUDPTransaction - * instance with a given ModbusUDPConnection - * to be used for transactions. - *

- * - * @param con a ModbusUDPConnection instance. - */ - public ModbusUDPTransaction(UDPMasterConnection con) { - setTerminal(con.getTerminal()); - } - - /** - * Sets the terminal on which this ModbusTransaction - * should be executed.

- * - * @param terminal a UDPSlaveTerminal. - */ - public void setTerminal(AbstractUDPTerminal terminal) { - this.terminal = terminal; - if (terminal.isActive()) { - transport = terminal.getTransport(); - } - } - - @Override - public void execute() throws ModbusIOException, ModbusSlaveException, ModbusException { - - //1. assert executeability - assertExecutable(); - //2. open the connection if not connected - if (!terminal.isActive()) { - try { - terminal.activate(); - transport = terminal.getTransport(); - } - catch (Exception ex) { - logger.debug("Terminal activation failed.", ex); - throw new ModbusIOException("Activation failed"); - } - } - - //3. Retry transaction retries times, in case of - //I/O Exception problems. - int retryCount = 0; - while (retryCount <= retries) { - try { - //3. write request, and read response, - // while holding the lock on the IO object - synchronized (MUTEX) { - //write request message - transport.writeRequest(request); - //read response message - response = transport.readResponse(); - break; - } - } - catch (ModbusIOException ex) { - retryCount++; - if (retryCount > retries) { - logger.error("Cannot send UDP message", ex); - } - else { - ModbusUtil.sleep(getRandomSleepTime(retryCount)); - } - } - } - - //4. deal with "application level" exceptions - if (response instanceof ExceptionResponse) { - throw new ModbusSlaveException(((ExceptionResponse)response).getExceptionCode()); - } - - //toggle the id - incrementTransactionID(); - } - - /** - * Asserts if this ModbusTCPTransaction is - * executable. - * - * @throws ModbusException if this transaction cannot be - * asserted as executable. - */ - private void assertExecutable() throws ModbusException { - if (request == null || terminal == null) { - throw new ModbusException("Assertion failed, transaction not executable"); - } - } - - /** - * Toggles the transaction identifier, to ensure - * that each transaction has a distinctive - * identifier.
- * When the maximum value of 65535 has been reached, - * the identifiers will start from zero again. - */ - private void incrementTransactionID() { - if (isCheckingValidity()) { - if (transactionID >= Modbus.MAX_TRANSACTION_ID) { - transactionID = Modbus.DEFAULT_TRANSACTION_ID; - } - else { - transactionID++; - } - } - request.setTransactionID(getTransactionID()); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransport.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransport.java deleted file mode 100644 index 501343c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/ModbusUDPTransport.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.msg.ModbusMessage; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.net.AbstractUDPTerminal; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.util.Arrays; - -/** - * Class that implements the Modbus UDP transport flavor. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusUDPTransport extends AbstractModbusTransport { - - private static final Logger logger = LoggerFactory.getLogger(ModbusUDPTransport.class); - - //instance attributes - private AbstractUDPTerminal terminal; - private final BytesOutputStream byteOutputStream = new BytesOutputStream(Modbus.MAX_MESSAGE_LENGTH); - private final BytesInputStream byteInputStream = new BytesInputStream(Modbus.MAX_MESSAGE_LENGTH); - - /** - * Constructs a new ModbusTransport instance, - * for a given UDPTerminal. - *

- * - * @param terminal the UDPTerminal used for message transport. - */ - public ModbusUDPTransport(AbstractUDPTerminal terminal) { - this.terminal = terminal; - } - - @Override - public void setTimeout(int time) { - super.setTimeout(time); - if (terminal != null) { - terminal.setTimeout(timeout); - } - } - - @Override - public void close() throws IOException { - } - - @Override - public ModbusTransaction createTransaction() { - ModbusUDPTransaction trans = new ModbusUDPTransaction(); - trans.setTerminal(terminal); - return trans; - } - - @Override - public void writeResponse(ModbusResponse msg) throws ModbusIOException { - writeMessage(msg); - } - - @Override - public void writeRequest(ModbusRequest msg) throws ModbusIOException { - writeMessage(msg); - } - - @Override - public ModbusRequest readRequest(AbstractModbusListener listener) throws ModbusIOException { - try { - ModbusRequest req; - synchronized (byteInputStream) { - byteInputStream.reset(terminal.receiveMessage()); - byteInputStream.skip(7); - int functionCode = byteInputStream.readUnsignedByte(); - byteInputStream.reset(); - req = ModbusRequest.createModbusRequest(functionCode); - req.readFrom(byteInputStream); - } - return req; - } - catch (Exception ex) { - throw new ModbusIOException("I/O exception - failed to read", ex); - } - } - - @Override - public ModbusResponse readResponse() throws ModbusIOException { - - try { - ModbusResponse res; - synchronized (byteInputStream) { - byteInputStream.reset(terminal.receiveMessage()); - byteInputStream.skip(7); - int functionCode = byteInputStream.readUnsignedByte(); - byteInputStream.reset(); - res = ModbusResponse.createModbusResponse(functionCode); - res.readFrom(byteInputStream); - } - return res; - } - catch (InterruptedIOException ioex) { - throw new ModbusIOException("Socket was interrupted", ioex); - } - catch (Exception ex) { - logger.debug("I/O exception while reading modbus response.", ex); - throw new ModbusIOException("I/O exception - failed to read - %s", ex.getMessage()); - } - } - - /** - * Writes the request/response message to the port - * @param msg Message to write - * @throws ModbusIOException If the port cannot be written to - */ - private void writeMessage(ModbusMessage msg) throws ModbusIOException { - try { - synchronized (byteOutputStream) { - int len = msg.getOutputLength(); - byteOutputStream.reset(); - msg.writeTo(byteOutputStream); - byte data[] = byteOutputStream.getBuffer(); - data = Arrays.copyOf(data, len); - terminal.sendMessage(data); - } - } - catch (Exception ex) { - throw new ModbusIOException("I/O exception - failed to write", ex); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/io/NonWordDataHandler.java b/app/src/main/java/com/ghgande/j2mod/modbus/io/NonWordDataHandler.java deleted file mode 100644 index 29fc3a5..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/io/NonWordDataHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.io; - -import java.io.DataInput; -import java.io.EOFException; -import java.io.IOException; - -/** - * Interface implementing a non word data handler for the read/write multiple - * register commands. - * - * This interface can be used by any class which works with multiple words of - * data for a non-standard data item. For example, message may involve data - * items which are floating point values or string. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - * @deprecated In the interests of keeping the library simple, this will be removed in a future release - */ -@Deprecated -public interface NonWordDataHandler { - - /** - * Returns the intermediate raw non-word data. - * - *

- * An implementation would need to provide a means of converting between the - * raw byte data and the registers that are present in actual messages. - * - * @return the raw data as byte[]. - */ - byte[] getData(); - - /** - * Reads the non-word raw data based on an arbitrary implemented structure. - * - * @param in the DataInput to read from. - * @param reference to specify the offset as int. - * @param count to specify the amount of bytes as int. - * - * @throws IOException if I/O fails. - * @throws EOFException if the stream ends before all data is read. - */ - void readData(DataInput in, int reference, int count) throws IOException, EOFException; - - /** - * Returns the word count of the data. Note that this should be the length - * of the byte array divided by two. - * - * @return the number of words the data consists of. - */ - int getWordCount(); - - /** - * Commits the data if it has been read into an intermediate repository. - * - *

- * This method is called for a message (for example, a - * WriteMultipleRegistersRequest instance) when finished with - * reading, for creating a response. - * - * @return -1 if the commit was successful, a Modbus exception code valid - * for the read/write multiple registers commands otherwise. - */ - int commitUpdate(); - - /** - * Prepares the raw data, putting it together from a backing data store. - * - *

- * This method is called for a message (for example, * ReadMultipleRegistersRequest) when finished with reading, for - * creating a response. - * - * @param reference to specify the offset as int. - * @param count to specify the number of bytes as int. - */ - void prepareData(int reference, int count); -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ExceptionResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ExceptionResponse.java deleted file mode 100644 index b599327..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ExceptionResponse.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing aModbusResponse that represents an exception. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ExceptionResponse extends ModbusResponse { - - // instance attributes - private int exceptionCode = -1; - - /** - * Constructs a new ExceptionResponse instance with a given - * function code and an exception code. The function code will be - * automatically increased with the exception offset. - * - * @param fc the function code as int. - * @param exc the exception code as int. - */ - public ExceptionResponse(int fc, int exc) { - - // One byte of data. - setDataLength(1); - setFunctionCode(fc | Modbus.EXCEPTION_OFFSET); - - exceptionCode = exc; - } - - /** - * Constructs a new ExceptionResponse instance with a given - * function code. ORs the exception offset automatically. - * - * @param fc the function code as int. - */ - public ExceptionResponse(int fc) { - - // One byte of data. - setDataLength(1); - setFunctionCode(fc | Modbus.EXCEPTION_OFFSET); - } - - /** - * Constructs a new ExceptionResponse instance with no function - * or exception code. - */ - public ExceptionResponse() { - - // One byte of data. - setDataLength(1); - } - - /** - * Returns the Modbus exception code of this ExceptionResponse. - *

- * - * @return the exception code as int. - */ - public int getExceptionCode() { - return exceptionCode; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(getExceptionCode()); - } - - /** - * readData() - * - * read the single byte of data, which is the exception code. - * @throws IOException If the data cannot be read from the socket/port - */ - public void readData(DataInput din) throws IOException { - exceptionCode = din.readUnsignedByte(); - } - - /** - * getMessage() - * - * return the exception type, which is the "message" for this response. - * - * @return -- byte array containing the 1 byte exception code. - */ - public byte[] getMessage() { - byte result[] = new byte[1]; - result[0] = (byte)getExceptionCode(); - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalAddressExceptionResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalAddressExceptionResponse.java deleted file mode 100644 index a61456d..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalAddressExceptionResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -/** - * @author Julie - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class IllegalAddressExceptionResponse extends ExceptionResponse { - - /** - * - */ - public IllegalAddressExceptionResponse() { - super(0, Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - public IllegalAddressExceptionResponse(int function) { - super(function, Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - /** - * Sets the function code - * @param fc Function code - */ - public void setFunctionCode(int fc) { - super.setFunctionCode(fc | Modbus.EXCEPTION_OFFSET); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionExceptionResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionExceptionResponse.java deleted file mode 100644 index 4f9ce42..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionExceptionResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -/** - * @author jfhaugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class IllegalFunctionExceptionResponse extends ExceptionResponse { - - /** - * - */ - public IllegalFunctionExceptionResponse() { - super(0, Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - public IllegalFunctionExceptionResponse(int function) { - super(function | Modbus.EXCEPTION_OFFSET, Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * Sets the function code - * @param fc Function code - */ - public void setFunctionCode(int fc) { - super.setFunctionCode(fc | Modbus.EXCEPTION_OFFSET); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionRequest.java deleted file mode 100644 index 33503d3..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalFunctionRequest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - *

- * Class implementing a ModbusRequest which is created for illegal or - * non implemented function codes. - * - *

- * This is just a helper class to keep the implementation patterns the same for - * all cases. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class IllegalFunctionRequest extends ModbusRequest { - - /** - * Constructs a new IllegalFunctionRequest instance for a given - * function code. - * - *

Used to implement slave devices when an illegal function code - * has been requested. - * - * @param function the function code as int. - */ - public IllegalFunctionRequest(int function) { - setFunctionCode(function); - } - - /** - * Constructs a new IllegalFunctionRequest instance for a given - * function code. - * - *

Used to implement slave devices when an illegal function code - * has been requested. - * - * @param unit Unit ID - * @param function the function code as int. - */ - public IllegalFunctionRequest(int unit, int function) { - setUnitID(unit); - setFunctionCode(function); - } - - /** - * There is no unit number associated with this exception. - * @return Modbus excepion response - */ - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new IllegalFunctionExceptionResponse(getFunctionCode()), true); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - public void writeData(DataOutput dout) throws IOException { - throw new RuntimeException(); - } - - /** - * Read all of the data that can be read. This is an unsupported - * function, so it may not be possible to know exactly how much data - * needs to be read. - * @throws IOException If the data cannot be read from the socket/port - */ - public void readData(DataInput din) throws IOException { - // skip all following bytes - int length = getDataLength(); - for (int i = 0; i < length; i++) { - din.readByte(); - } - } - - public byte[] getMessage() { - return null; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalValueExceptionResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalValueExceptionResponse.java deleted file mode 100644 index 05549e0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/IllegalValueExceptionResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -/** - * @author Julie - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class IllegalValueExceptionResponse extends ExceptionResponse { - - /** - * - */ - public IllegalValueExceptionResponse() { - super(0, Modbus.ILLEGAL_VALUE_EXCEPTION); - } - - public IllegalValueExceptionResponse(int function) { - super(function, Modbus.ILLEGAL_VALUE_EXCEPTION); - } - - /** - * Sets the function code - * @param fc Function code - */ - public void setFunctionCode(int fc) { - super.setFunctionCode(fc | Modbus.EXCEPTION_OFFSET); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterRequest.java deleted file mode 100644 index 65794c1..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterRequest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.procimg.Register; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Mask Write Register request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class MaskWriteRegisterRequest extends ModbusRequest { - private int reference; - private int andMask; - private int orMask; - - /** - * Constructs a new Mask Write Register request. - * - * @param ref Register - * @param andMask AND Mask to use - * @param orMask OR Mask to use - */ - public MaskWriteRegisterRequest(int ref, int andMask, int orMask) { - super(); - - setFunctionCode(Modbus.MASK_WRITE_REGISTER); - setReference(ref); - setAndMask(andMask); - setOrMask(orMask); - - setDataLength(6); - } - - /** - * Constructs a new Mask Write Register request. - * instance. - */ - public MaskWriteRegisterRequest() { - super(); - - setFunctionCode(Modbus.MASK_WRITE_REGISTER); - setDataLength(6); - } - - /** - * getReference - * @return the reference field - */ - public int getReference() { - return reference; - } - - /** - * setReference -- set the reference field. - * @param ref the reference field - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * getAndMask -- return the AND mask value; - * - * @return int - */ - public int getAndMask() { - return andMask; - } - - /** - * setAndMask -- set AND mask - * @param mask AND mask - */ - public void setAndMask(int mask) { - andMask = mask; - } - - /** - * getOrMask -- return the OR mask value; - * - * @return int - */ - public int getOrMask() { - return orMask; - } - - /** - * setOrMask -- set OR mask - * @param mask OR mask - */ - public void setOrMask(int mask) { - orMask = mask; - } - - /** - * getResponse -- create an empty response for this request. - * @return empty response for this request - */ - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new MaskWriteRegisterResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - MaskWriteRegisterResponse response; - - // Get the process image. - ProcessImage procimg = listener.getProcessImage(getUnitID()); - try { - Register register = procimg.getRegister(reference); - - /* - * Get the original value. The AND mask will first be - * applied to clear any bits, then the OR mask will be - * applied to set them. - */ - int value = register.getValue(); - value = (value & andMask) | (orMask & ~andMask); - - // Store the modified value back where it came from. - register.setValue(value); - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (MaskWriteRegisterResponse)getResponse(); - response.setReference(reference); - response.setAndMask(andMask); - response.setOrMask(orMask); - - return response; - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written from the socket/port - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- dummy function. There is no data with the request. - * @throws IOException If the data cannot be read from the socket/port - */ - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - andMask = din.readUnsignedShort(); - orMask = din.readUnsignedShort(); - } - - /** - * getMessage -- return an empty array as there is no data for - * this request. - * @return message payload - */ - public byte[] getMessage() { - byte results[] = new byte[6]; - - results[0] = (byte)(reference >> 8); - results[1] = (byte)(reference & 0xFF); - results[2] = (byte)(andMask >> 8); - results[3] = (byte)(andMask & 0xFF); - results[4] = (byte)(orMask >> 8); - results[5] = (byte)(orMask & 0xFF); - - return results; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterResponse.java deleted file mode 100644 index f22cb5f..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/MaskWriteRegisterResponse.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadMEIResponse. - * - * Derived from similar class for Read Coils response. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class MaskWriteRegisterResponse - extends ModbusResponse { - - // Message fields. - private int reference; - private int andMask; - private int orMask; - - /** - * Constructs a new ReportSlaveIDResponse - * instance. - */ - public MaskWriteRegisterResponse() { - super(); - setFunctionCode(Modbus.MASK_WRITE_REGISTER); - } - - /** - * getReference - * @return the reference field - */ - public int getReference() { - return reference; - } - - /** - * setReference -- set the reference field. - * @param ref Register value - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * getAndMask -- return the AND mask value; - * - * @return int - */ - public int getAndMask() { - return andMask; - } - - /** - * setAndMask -- set AND mask - * @param mask Mask to use - */ - public void setAndMask(int mask) { - andMask = mask; - } - - /** - * getOrMask -- return the OR mask value; - * - * @return int - */ - public int getOrMask() { - return orMask; - } - - /** - * setOrMask -- set OR mask - * @param mask OR bit mask - */ - public void setOrMask(int mask) { - orMask = mask; - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written to the socket/port - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a - * header, such as for Modbus/TCP, it will have been read - * already. - * @throws IOException If the data cannot be read from the socket/port - */ - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - andMask = din.readUnsignedShort(); - orMask = din.readUnsignedShort(); - } - - /** - * getMessage -- format the message into a byte array. - * @return Byte array of the message - */ - public byte[] getMessage() { - byte results[] = new byte[6]; - - results[0] = (byte)(reference >> 8); - results[1] = (byte)(reference & 0xFF); - results[2] = (byte)(andMask >> 8); - results[3] = (byte)(andMask & 0xFF); - results[4] = (byte)(orMask >> 8); - results[5] = (byte)(orMask & 0xFF); - - return results; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessage.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessage.java deleted file mode 100644 index be5693b..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessage.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Interface defining a ModbusMessage. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface ModbusMessage { - - /** - * Check the flag which indicates that this ModbusMessage is for a - * headless (serial, or headless networked) connection. - * @return is for a headless (serial, or headless networked) connection - */ - boolean isHeadless(); - - /** - * Sets the flag that marks this ModbusMessage as headless (for - * serial transport). - */ - void setHeadless(); - - /** - * Returns the transaction identifier of this ModbusMessage as - * int. - * - *

- * The identifier is a 2-byte (short) non negative integer value valid in - * the range of 0-65535. - * - * @return the transaction identifier as int. - */ - int getTransactionID(); - - /** - * Returns the protocol identifier of this ModbusMessage as - * int. - * - *

- * The identifier is a 2-byte (short) non negative integer value valid in - * the range of 0-65535. - * - * @return the protocol identifier as int. - */ - int getProtocolID(); - - /** - * Returns the length of the data appended after the protocol header. - *

- * - * @return the data length as int. - */ - int getDataLength(); - - /** - * Returns the unit identifier of this ModbusMessage as - * int. - * - *

- * The identifier is a 1-byte non negative integer value valid in the range - * of 0-255. - * - * @return the unit identifier as int. - */ - int getUnitID(); - - /** - * Returns the function code of this ModbusMessage as int.
- * The function code is a 1-byte non negative integer value valid in the - * range of 0-127. - * - *

- * Function codes are ordered in conformance classes their values are - * specified in com.ghgande.j2mod.modbus.Modbus. - * - * @return the function code as int. - * - * @see com.ghgande.j2mod.modbus.Modbus - */ - int getFunctionCode(); - - /** - * Returns the raw message as an array of bytes. - *

- * - * @return the raw message as byte[]. - */ - byte[] getMessage(); - - /** - * Returns the raw message as String containing a - * hexadecimal series of bytes. - * - *

- * This method is specially for debugging purposes, allowing the user to log - * the communication in a manner used in the specification document. - * - * @return the raw message as String containing a - * hexadecimal series of bytes. - */ - String getHexMessage(); - - /** - * Returns the number of bytes that will - * be written by {@link #writeTo(DataOutput)}. - * - * @return the number of bytes that will be written as int. - */ - int getOutputLength(); - - /** - * Writes this Transportable to the - * given DataOutput. - * - * @param dout the DataOutput to write to. - * - * @throws IOException if an I/O error occurs. - */ - void writeTo(DataOutput dout) throws IOException; - - /** - * Reads this Transportable from the given - * DataInput. - * - * @param din the DataInput to read from. - * - * @throws IOException if an I/O error occurs or the data - * is invalid. - */ - void readFrom(DataInput din) throws IOException; - - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessageImpl.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessageImpl.java deleted file mode 100644 index f9ebe20..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusMessageImpl.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.util.ModbusUtil; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Abstract class implementing a ModbusMessage. This class provides - * specialised implementations with the functionality they have in common. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class ModbusMessageImpl implements ModbusMessage { - - // instance attributes - private int transactionID = Modbus.DEFAULT_TRANSACTION_ID; - private int protocolID = Modbus.DEFAULT_PROTOCOL_ID; - private int dataLength; - private int unitID = Modbus.DEFAULT_UNIT_ID; - private int functionCode; - private boolean headless = false; // flag for header-less (serial) - - @Override - public boolean isHeadless() { - return headless; - } - - @Override - public void setHeadless() { - headless = true; - } - - @Override - public int getTransactionID() { - return transactionID & 0x0000FFFF; - } - - /** - * Sets the transaction identifier of this ModbusMessage. - * - *

- * The identifier must be a 2-byte (short) non negative integer value valid - * in the range of 0-65535.
- * - * @param tid the transaction identifier as int. - */ - public void setTransactionID(int tid) { - transactionID = tid & 0x0000FFFF; - } - - @Override - public int getProtocolID() { - return protocolID; - } - - /** - * Sets the protocol identifier of this ModbusMessage. - *

- * The identifier should be a 2-byte (short) non negative integer value - * valid in the range of 0-65535.
- *

- * - * @param pid the protocol identifier as int. - */ - public void setProtocolID(int pid) { - protocolID = pid; - } - - @Override - public int getDataLength() { - return dataLength; - } - - /** - * Sets the length of the data appended after the protocol header. - * - *

- * Note that this library, a bit in contrast to the specification, counts - * the unit identifier and the function code in the header, because it is - * part of each and every message. Thus this method will add two (2) to the - * passed in integer value. - * - *

- * This method does not include the length of a final CRC/LRC for those - * protocols which requirement. - * - * @param length the data length as int. - */ - public void setDataLength(int length) { - if (length < 0 || length + 2 > 255) { - throw new IllegalArgumentException("Invalid length: " + length); - } - - dataLength = length + 2; - } - - @Override - public int getUnitID() { - return unitID; - } - - /** - * Sets the unit identifier of this ModbusMessage.
- * The identifier should be a 1-byte non negative integer value valid in the - * range of 0-255. - * - * @param num the unit identifier number to be set. - */ - public void setUnitID(int num) { - unitID = num; - } - - @Override - public int getFunctionCode() { - return functionCode; - } - - /** - * Sets the function code of this ModbusMessage.
- * The function code should be a 1-byte non negative integer value valid in - * the range of 0-127.
- * Function codes are ordered in conformance classes their values are - * specified in com.ghgande.j2mod.modbus.Modbus. - * - * @param code the code of the function to be set. - * - * @see com.ghgande.j2mod.modbus.Modbus - */ - protected void setFunctionCode(int code) { - functionCode = code; - } - - @Override - public String getHexMessage() { - return ModbusUtil.toHex(this); - } - - /** - * Sets the headless flag of this message. - * - * @param b true if headless, false otherwise. - */ - public void setHeadless(boolean b) { - headless = b; - } - - @Override - public int getOutputLength() { - int l = 2 + getDataLength(); - if (!isHeadless()) { - l = l + 4; - } - return l; - } - - @Override - public void writeTo(DataOutput dout) throws IOException { - - if (!isHeadless()) { - dout.writeShort(getTransactionID()); - dout.writeShort(getProtocolID()); - dout.writeShort(getDataLength()); - } - dout.writeByte(getUnitID()); - dout.writeByte(getFunctionCode()); - - writeData(dout); - } - - @Override - public void readFrom(DataInput din) throws IOException { - if (!isHeadless()) { - setTransactionID(din.readUnsignedShort()); - setProtocolID(din.readUnsignedShort()); - dataLength = din.readUnsignedShort(); - } - setUnitID(din.readUnsignedByte()); - setFunctionCode(din.readUnsignedByte()); - readData(din); - } - - /** - * Writes the subclass specific data to the given DataOutput. - * - * @param dout the DataOutput to be written to. - * - * @throws IOException if an I/O related error occurs. - */ - public abstract void writeData(DataOutput dout) throws IOException; - - /** - * Reads the subclass specific data from the given DataInput instance. - * - * @param din the DataInput to read from. - * - * @throws IOException if an I/O related error occurs. - */ - public abstract void readData(DataInput din) throws IOException; - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusRequest.java deleted file mode 100644 index 286c590..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusRequest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -/** - * Abstract class implementing a ModbusRequest. This class provides - * specialised implementations with the functionality they have in common. - * - * @author Dieter Wimberger - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class ModbusRequest extends ModbusMessageImpl { - - /** - * Factory method creating the required specialized ModbusRequest - * instance. - * - * @param functionCode the function code of the request as int. - * - * @return a ModbusRequest instance specific for the given function type. - */ - public static ModbusRequest createModbusRequest(int functionCode) { - ModbusRequest request; - - switch (functionCode) { - case Modbus.READ_COILS: - request = new ReadCoilsRequest(); - break; - case Modbus.READ_INPUT_DISCRETES: - request = new ReadInputDiscretesRequest(); - break; - case Modbus.READ_MULTIPLE_REGISTERS: - request = new ReadMultipleRegistersRequest(); - break; - case Modbus.READ_INPUT_REGISTERS: - request = new ReadInputRegistersRequest(); - break; - case Modbus.WRITE_COIL: - request = new WriteCoilRequest(); - break; - case Modbus.WRITE_SINGLE_REGISTER: - request = new WriteSingleRegisterRequest(); - break; - case Modbus.WRITE_MULTIPLE_COILS: - request = new WriteMultipleCoilsRequest(); - break; - case Modbus.WRITE_MULTIPLE_REGISTERS: - request = new WriteMultipleRegistersRequest(); - break; - case Modbus.READ_EXCEPTION_STATUS: - request = new ReadExceptionStatusRequest(); - break; - case Modbus.READ_SERIAL_DIAGNOSTICS: - request = new ReadSerialDiagnosticsRequest(); - break; - case Modbus.READ_COMM_EVENT_COUNTER: - request = new ReadCommEventCounterRequest(); - break; - case Modbus.READ_COMM_EVENT_LOG: - request = new ReadCommEventLogRequest(); - break; - case Modbus.REPORT_SLAVE_ID: - request = new ReportSlaveIDRequest(); - break; - case Modbus.READ_FILE_RECORD: - request = new ReadFileRecordRequest(); - break; - case Modbus.WRITE_FILE_RECORD: - request = new WriteFileRecordRequest(); - break; - case Modbus.MASK_WRITE_REGISTER: - request = new MaskWriteRegisterRequest(); - break; - case Modbus.READ_WRITE_MULTIPLE: - request = new ReadWriteMultipleRequest(); - break; - case Modbus.READ_FIFO_QUEUE: - request = new ReadFIFOQueueRequest(); - break; - case Modbus.READ_MEI: - request = new ReadMEIRequest(); - break; - default: - request = new IllegalFunctionRequest(functionCode); - break; - } - return request; - } - - /** - * Returns the ModbusResponse that correlates with this - * ModbusRequest. - * - *

- * The response must include the unit number, function code, as well as any - * transport-specific header information. - * - *

- * This method is used to create an empty response which must be populated - * by the caller. It is commonly used to un-marshal responses from Modbus - * slaves. - * - * @return the corresponding ModbusResponse. - */ - public abstract ModbusResponse getResponse(); - - /** - * Returns the ModbusResponse that represents the answer to this - * ModbusRequest. - * - *

- * The implementation should take care about assembling the reply to this - * ModbusRequest. - * - *

- * This method is used to create responses from the process image associated - * with the listener. It is commonly used to implement Modbus slave - * instances. - * - * @param listener Listener that received the request - * @return the corresponding ModbusResponse. - */ - public abstract ModbusResponse createResponse(AbstractModbusListener listener); - - /** - * Factory method for creating exception responses with the given exception - * code. - * - * @param code the code of the exception. - * - * @return a ModbusResponse instance representing the exception response. - */ - public ModbusResponse createExceptionResponse(int code) { - return updateResponseWithHeader(new ExceptionResponse(getFunctionCode(), code), true); - } - - /** - * Updates the response with the header information to match the request - * - * @param response Response to update - * @return Updated response - */ - ModbusResponse updateResponseWithHeader(ModbusResponse response) { - return updateResponseWithHeader(response, false); - } - - /** - * Updates the response with the header information to match the request - * - * @param response Response to update - * @param ignoreFunctionCode True if the function code should stay unmolested - * @return Updated response - */ - ModbusResponse updateResponseWithHeader(ModbusResponse response, boolean ignoreFunctionCode) { - - // transfer header data - response.setHeadless(isHeadless()); - if (!isHeadless()) { - response.setTransactionID(getTransactionID()); - response.setProtocolID(getProtocolID()); - } - else { - response.setHeadless(); - } - response.setUnitID(getUnitID()); - if (!ignoreFunctionCode) { - response.setFunctionCode(getFunctionCode()); - } - return response; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusResponse.java deleted file mode 100644 index 41d2cea..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ModbusResponse.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; - -import static com.ghgande.j2mod.modbus.msg.ModbusResponse.AuxiliaryMessageTypes.NONE; - -/** - * Abstract class implementing a ModbusResponse. This class provides - * specialised implementations with the functionality they have in common. - * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class ModbusResponse extends ModbusMessageImpl { - - private static final Logger logger = LoggerFactory.getLogger(ModbusResponse.class); - - public enum AuxiliaryMessageTypes { - NONE, UNIT_ID_MISSMATCH - } - private AuxiliaryMessageTypes auxiliaryType = NONE; - - /** - * Factory method creating the required specialized ModbusResponse - * instance. - * - * @param functionCode the function code of the response as int. - * - * @return a ModbusResponse instance specific for the given function code. - */ - public static ModbusResponse createModbusResponse(int functionCode) { - ModbusResponse response; - - switch (functionCode) { - case Modbus.READ_COILS: - response = new ReadCoilsResponse(); - break; - case Modbus.READ_INPUT_DISCRETES: - response = new ReadInputDiscretesResponse(); - break; - case Modbus.READ_MULTIPLE_REGISTERS: - response = new ReadMultipleRegistersResponse(); - break; - case Modbus.READ_INPUT_REGISTERS: - response = new ReadInputRegistersResponse(); - break; - case Modbus.WRITE_COIL: - response = new WriteCoilResponse(); - break; - case Modbus.WRITE_SINGLE_REGISTER: - response = new WriteSingleRegisterResponse(); - break; - case Modbus.WRITE_MULTIPLE_COILS: - response = new WriteMultipleCoilsResponse(); - break; - case Modbus.WRITE_MULTIPLE_REGISTERS: - response = new WriteMultipleRegistersResponse(); - break; - case Modbus.READ_EXCEPTION_STATUS: - response = new ReadExceptionStatusResponse(); - break; - case Modbus.READ_SERIAL_DIAGNOSTICS: - response = new ReadSerialDiagnosticsResponse(); - break; - case Modbus.READ_COMM_EVENT_COUNTER: - response = new ReadCommEventCounterResponse(); - break; - case Modbus.READ_COMM_EVENT_LOG: - response = new ReadCommEventLogResponse(); - break; - case Modbus.REPORT_SLAVE_ID: - response = new ReportSlaveIDResponse(); - break; - case Modbus.READ_FILE_RECORD: - response = new ReadFileRecordResponse(); - break; - case Modbus.WRITE_FILE_RECORD: - response = new WriteFileRecordResponse(); - break; - case Modbus.MASK_WRITE_REGISTER: - response = new MaskWriteRegisterResponse(); - break; - case Modbus.READ_WRITE_MULTIPLE: - response = new ReadWriteMultipleResponse(); - break; - case Modbus.READ_FIFO_QUEUE: - response = new ReadFIFOQueueResponse(); - break; - case Modbus.READ_MEI: - response = new ReadMEIResponse(); - break; - default: - if ((functionCode & 0x80) != 0) { - response = new ExceptionResponse(functionCode); - } - else { - response = new ExceptionResponse(); - } - break; - } - return response; - } - - /** - * Utility method to set the raw data of the message. Should not be used - * except under rare circumstances. - *

- * - * @param msg the byte[] resembling the raw modbus response - * message. - */ - protected void setMessage(byte[] msg) { - try { - readData(new DataInputStream(new ByteArrayInputStream(msg))); - } - catch (IOException ex) { - logger.error("Problem setting response message - {}", ex.getMessage()); - } - } - - /** - * Returns the auxiliary type of this response message - * Useful for adding extra information to the message that can be used by downstream processing - * - * @return Auxiliary type - */ - public AuxiliaryMessageTypes getAuxiliaryType() { - return auxiliaryType; - } - - /** - * Sets the auxiliary type of this response - * - * @param auxiliaryType Type - */ - public void setAuxiliaryType(AuxiliaryMessageTypes auxiliaryType) { - this.auxiliaryType = auxiliaryType; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsRequest.java deleted file mode 100644 index b8bd207..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsRequest.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.DigitalOut; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadCoilsRequest. The implementation directly - * correlates with the class 1 function read coils (FC 1). It - * encapsulates the corresponding request message. - * - *

- * Coils are understood as bits that can be manipulated (i.e. set or unset). - * - * @author Dieter Wimberger - * @author jfhaugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCoilsRequest extends ModbusRequest { - - // instance attributes - private int reference; - private int bitCount; - - /** - * Constructs a new ReadCoilsRequest instance. - */ - public ReadCoilsRequest() { - super(); - - setFunctionCode(Modbus.READ_COILS); - setDataLength(4); - } - - /** - * Constructs a new ReadCoilsRequest instance with a given - * reference and count of coils (i.e. bits) to be read. - *

- * - * @param ref the reference number of the register to read from. - * @param count the number of bits to be read. - */ - public ReadCoilsRequest(int ref, int count) { - super(); - - setFunctionCode(Modbus.READ_COILS); - setDataLength(4); - - setReference(ref); - setBitCount(count); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadCoilsResponse(bitCount)); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ModbusResponse response; - DigitalOut[] douts; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - // 2. get input discretes range - try { - douts = procimg.getDigitalOutRange(getReference(), getBitCount()); - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = getResponse(); - - // Populate the discrete values from the process image. - for (int i = 0; i < douts.length; i++) { - ((ReadCoilsResponse)response).setCoilStatus(i, douts[i].isSet()); - } - - return response; - } - - /** - * Returns the reference of the register to to start reading from with this - * ReadCoilsRequest. - *

- * - * @return the reference of the register to start reading from as - * int. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to start reading from with this - * ReadCoilsRequest. - *

- * - * @param ref the reference of the register to start reading from. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the number of bits (i.e. coils) to be read with this - * ReadCoilsRequest. - *

- * - * @return the number of bits to be read. - */ - public int getBitCount() { - return bitCount; - } - - /** - * Sets the number of bits (i.e. coils) to be read with this - * ReadCoilsRequest. - *

- * - * @param count the number of bits to be read. - */ - public void setBitCount(int count) { - if (count > Modbus.MAX_BITS) { - throw new IllegalArgumentException("Maximum bitcount exceeded"); - } - else { - bitCount = count; - } - } - - @Override - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - @Override - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - bitCount = din.readUnsignedShort(); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)((reference & 0xff)); - result[2] = (byte)((bitCount >> 8) & 0xff); - result[3] = (byte)((bitCount & 0xff)); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsResponse.java deleted file mode 100644 index 33bad4d..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCoilsResponse.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.util.BitVector; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadCoilsResponse. - * The implementation directly correlates with the class 1 - * function read coils (FC 1). It encapsulates - * the corresponding response message. - *

- * Coils are understood as bits that can be manipulated - * (i.e. set or unset). - * - * @author Dieter Wimberger - * @version 1.2rc1 (09/11/2004) - */ - -/** - * Completed re-implementation 1/10/2011 - * - * Created getMessage() method to abstractly create the message - * data. - * Cleaned up the constructors. - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCoilsResponse extends ModbusResponse { - private BitVector coils; - - /** - * ReadCoilsResponse -- create an empty response message to be - * filled in later. - */ - public ReadCoilsResponse() { - setFunctionCode(Modbus.READ_COILS); - setDataLength(1); - coils = null; - } - - /** - * ReadCoilsResponse -- create a response for a given number of - * coils. - * - * @param count the number of bits to be read. - */ - public ReadCoilsResponse(int count) { - setFunctionCode(Modbus.READ_COILS); - coils = new BitVector(count); - setDataLength(coils.byteSize() + 1); - } - - /** - * getBitCount -- return the number of coils - * - * @return number of defined coils - */ - public int getBitCount() { - if (coils == null) { - return 0; - } - else { - return coils.size(); - } - } - - /** - * getCoils -- get the coils bit vector. - * - * The coils vector may be read (when operating as a master) or - * written (when operating as a slave). - * - * @return BitVector containing the coils. - */ - public BitVector getCoils() { - return coils; - } - - /** - * Convenience method that returns the state - * of the bit at the given index. - *

- * - * @param index the index of the coil for which - * the status should be returned. - * - * @return true if set, false otherwise. - * - * @throws IndexOutOfBoundsException if the - * index is out of bounds - */ - public boolean getCoilStatus(int index) throws IndexOutOfBoundsException { - - if (index < 0) { - throw new IllegalArgumentException(index + " < 0"); - } - - if (index > coils.size()) { - throw new IndexOutOfBoundsException(index + " > " + coils.size()); - } - - return coils.getBit(index); - } - - /** - * Sets the status of the given coil. - * - * @param index the index of the coil to be set. - * @param b true if to be set, false for reset. - */ - public void setCoilStatus(int index, boolean b) { - if (index < 0) { - throw new IllegalArgumentException(index + " < 0"); - } - - if (index > coils.size()) { - throw new IndexOutOfBoundsException(index + " > " + coils.size()); - } - - coils.setBit(index, b); - } - - public void writeData(DataOutput output) throws IOException { - byte result[] = getMessage(); - - output.write(result); - } - - public void readData(DataInput input) throws IOException { - int count = input.readUnsignedByte(); - byte[] data = new byte[count]; - - input.readFully(data, 0, count); - coils = BitVector.createBitVector(data); - setDataLength(count + 1); - } - - public byte[] getMessage() { - int len = 1 + coils.byteSize(); - byte result[] = new byte[len]; - - result[0] = (byte)coils.byteSize(); - System.arraycopy(coils.getBytes(), 0, result, 1, coils.byteSize()); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterRequest.java deleted file mode 100644 index 7709439..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterRequest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read MEI Data request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCommEventCounterRequest extends ModbusRequest { - - /** - * Constructs a new Report Slave ID request instance. - */ - public ReadCommEventCounterRequest() { - super(); - - setFunctionCode(Modbus.READ_COMM_EVENT_COUNTER); - - // There is no additional data in this request. - setDataLength(0); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadCommEventCounterResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- dummy function. There is no additional data - * to read. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - } - - /** - * getMessage - * @return an empty array as there is no data for this request - */ - public byte[] getMessage() { - - return new byte[0]; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterResponse.java deleted file mode 100644 index c12a709..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventCounterResponse.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadCommEventCounterResponse. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCommEventCounterResponse extends ModbusResponse { - - // Message fields. - private int status; - private int events; - - /** - * Constructs a new ReportSlaveIDResponse instance. - */ - public ReadCommEventCounterResponse() { - super(); - - setFunctionCode(Modbus.READ_COMM_EVENT_COUNTER); - setDataLength(4); - } - - /** - * getStatus -- get the device's status. - * - * @return int - */ - public int getStatus() { - return status; - } - - /** - * setStatus -- set the device's status. - * - * @param status int - */ - public void setStatus(int status) { - if (status != 0 && status != 0xFFFF) { - throw new IllegalArgumentException("Illegal status value: " + status); - } - - this.status = status; - } - - /** - * getEvents -- get device's event counter. - * @return Event count - */ - public int getEventCount() { - return events; - } - - /** - * setEvents -- set the device's event counter. - * @param count Event count - */ - public void setEventCount(int count) { - events = count; - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a header, - * such as for Modbus/TCP, it will have been read already. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - status = din.readUnsignedShort(); - events = din.readUnsignedShort(); - } - - /** - * getMessage -- format the message into a byte array. - * @return Response as byte array - */ - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)(status >> 8); - result[1] = (byte)(status & 0xFF); - result[2] = (byte)(events >> 8); - result[3] = (byte)(events & 0xFF); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogRequest.java deleted file mode 100644 index 04e27ee..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogRequest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read MEI Data request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCommEventLogRequest extends ModbusRequest { - - /** - * Constructs a new Get Comm Event Log - * instance. - */ - public ReadCommEventLogRequest() { - super(); - - setFunctionCode(Modbus.READ_COMM_EVENT_LOG); - - // There is no additional data in this request. - setDataLength(0); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadCommEventLogResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- dummy function. There is no data with the request. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - } - - /** - * getMessage - * @return an empty array as there is no data for this request - */ - public byte[] getMessage() { - - return new byte[0]; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogResponse.java deleted file mode 100644 index 8911aa7..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadCommEventLogResponse.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadCommEventCounterResponse. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadCommEventLogResponse extends ModbusResponse { - - // Message fields. - private int byteCount; - private int status; - private int eventCount; - private int messageCount; - private byte[] events; - - /** - * Constructs a new ReadCommEventLogResponse instance. - */ - public ReadCommEventLogResponse() { - super(); - - setFunctionCode(Modbus.READ_COMM_EVENT_LOG); - setDataLength(7); - } - - /** - * getStatus -- get the device's status. - * - * @return int - */ - public int getStatus() { - return status; - } - - /** - * setStatus -- set the device's status. - * - * @param status Status to set - */ - public void setStatus(int status) { - this.status = status; - } - - /** - * getEvents -- get device's event counter. - * @return Number of events - */ - public int getEventCount() { - return eventCount; - } - - /** - * setEventCount -- set the device's event counter. - * @param count Set the event count - */ - public void setEventCount(int count) { - eventCount = count; - } - - /** - * getMessageCount -- get device's message counter. - * - * @return Number of messages - */ - public int getMessageCount() { - return messageCount; - } - - /** - * setMessageCount -- set device's message counter. - * @param count Number of messages - */ - public void setMessageCount(int count) { - messageCount = count; - } - - /** - * getEvent -- get an event from the event log. - * @param index Index of the event - * @return Event ID - */ - public int getEvent(int index) { - if (events == null || index < 0 || index >= events.length) { - throw new IndexOutOfBoundsException("index = " + index + ", limit = " + (events == null ? "null" : events.length)); - } - - return events[index] & 0xFF; - } - - public byte[] getEvents() { - if (events == null) { - return null; - } - - byte[] result = new byte[events.length]; - System.arraycopy(events, 0, result, 0, events.length); - - return result; - } - - public void setEvents(byte[] events) { - if (events.length > 64) { - throw new IllegalArgumentException("events list too big (> 64 bytes)"); - } - - events = new byte[events.length]; - if (events.length > 0) { - System.arraycopy(events, 0, events, 0, events.length); - } - } - - public void setEvents(int count) { - if (count < 0 || count > 64) { - throw new IllegalArgumentException("invalid event list size (0 <= count <= 64)"); - } - - events = new byte[count]; - } - - /** - * setEvent -- store an event number in the event log - * @param index Event position - * @param event Event ID - */ - public void setEvent(int index, int event) { - if (events == null || index < 0 || index >= events.length) { - throw new IndexOutOfBoundsException("index = " + index + ", limit = " + (events == null ? "null" : events.length)); - } - - events[index] = (byte)event; - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a header, - * such as for Modbus/TCP, it will have been read already. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - byteCount = din.readByte(); - status = din.readUnsignedShort(); - eventCount = din.readUnsignedShort(); - messageCount = din.readUnsignedShort(); - - events = new byte[byteCount - 6]; - - if (events.length > 0) { - din.readFully(events, 0, events.length); - } - } - - /** - * getMessage -- format the message into a byte array. - * @return Response as byte array - */ - public byte[] getMessage() { - byte result[] = new byte[events.length + 7]; - - result[0] = (byte)(byteCount = events.length + 6); - result[1] = (byte)(status >> 8); - result[2] = (byte)(status & 0xFF); - result[3] = (byte)(eventCount >> 8); - result[4] = (byte)(eventCount & 0xFF); - result[5] = (byte)(messageCount >> 8); - result[6] = (byte)(messageCount & 0xFF); - - System.arraycopy(events, 0, result, 7, events.length); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusRequest.java deleted file mode 100644 index a13c3f5..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusRequest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read Exception Status request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadExceptionStatusRequest extends ModbusRequest { - - /** - * Constructs a new Read Exception Status request - * instance. - */ - public ReadExceptionStatusRequest() { - super(); - - setFunctionCode(Modbus.READ_EXCEPTION_STATUS); - - // There is no additional data in this request. - setDataLength(0); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadExceptionStatusResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- dummy function. There is no data with the request. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - } - - /** - * getMessage - * @return an empty array as there is no data for this request - */ - public byte[] getMessage() { - - return new byte[0]; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusResponse.java deleted file mode 100644 index 7f26e66..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadExceptionStatusResponse.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadCommEventCounterResponse. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadExceptionStatusResponse extends ModbusResponse { - - // Message fields. - private int status; - - /** - * Constructs a new ReadExceptionStatusResponse instance. - */ - public ReadExceptionStatusResponse() { - super(); - - setFunctionCode(Modbus.READ_EXCEPTION_STATUS); - setDataLength(1); - } - - /** - * getStatus -- get the device's status. - * - * @return int - */ - public int getStatus() { - return status; - } - - /** - * setStatus -- set the device's status. - * - * @param status Status to set - */ - public void setStatus(int status) { - this.status = status; - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a header, - * such as for Modbus/TCP, it will have been read already. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - status = din.readByte() & 0xFF; - } - - /** - * getMessage -- format the message into a byte array. - * @return Response as byte array - */ - public byte[] getMessage() { - byte result[] = new byte[1]; - - result[0] = (byte)(status & 0xFF); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueRequest.java deleted file mode 100644 index 86885d7..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueRequest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.procimg.Register; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read FIFO Queue request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadFIFOQueueRequest extends ModbusRequest { - - private int reference; - - /** - * Constructs a new Read FIFO Queue request instance. - */ - public ReadFIFOQueueRequest() { - super(); - - setFunctionCode(Modbus.READ_FIFO_QUEUE); - setDataLength(2); - } - - /** - * getReference -- get the queue register number. - * - * @return int - */ - public int getReference() { - return reference; - } - - /** - * setReference -- set the queue register number. - * - * @param ref Register - */ - public void setReference(int ref) { - reference = ref; - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadFIFOQueueResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadFIFOQueueResponse response; - InputRegister[] registers; - - // Get the process image. - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - try { - // Get the FIFO queue location and read the count of available - // registers. - Register queue = procimg.getRegister(reference); - int count = queue.getValue(); - if (count < 0 || count > 31) { - return createExceptionResponse(Modbus.ILLEGAL_VALUE_EXCEPTION); - } - registers = procimg.getRegisterRange(reference + 1, count); - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (ReadFIFOQueueResponse)getResponse(); - response.setRegisters(registers); - - return response; - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If cannot write - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- read the reference word. - * @throws IOException If cannot read - */ - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - } - - /** - * getMessage - * @return an empty array as there is no data for this request - */ - public byte[] getMessage() { - byte results[] = new byte[2]; - - results[0] = (byte)(reference >> 8); - results[1] = (byte)(reference & 0xFF); - - return results; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueResponse.java deleted file mode 100644 index 5163893..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFIFOQueueResponse.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.SimpleInputRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a ReadFIFOQueueResponse. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadFIFOQueueResponse extends ModbusResponse { - - // Message fields. - private int count; - private InputRegister registers[]; - - /** - * Constructs a new ReadFIFOQueueResponse instance. - */ - public ReadFIFOQueueResponse() { - super(); - - setFunctionCode(Modbus.READ_FIFO_QUEUE); - - count = 0; - registers = new InputRegister[0]; - - setDataLength(7); - } - - /** - * getWordCount -- get the queue size. - * - * @return Word count int - */ - synchronized public int getWordCount() { - return count; - } - - /** - * setWordCount -- set the queue size. - * - * @param ref Register - */ - public synchronized void setWordCount(int ref) { - if (ref < 0 || ref > 31) { - throw new IllegalArgumentException(); - } - count = ref; - } - - synchronized public int[] getRegisters() { - int values[] = new int[count]; - - for (int i = 0; i < count; i++) { - values[i] = getRegister(i); - } - - return values; - } - - /** - * setRegisters -- set the device's status. - * - * @param regs Array of registers - */ - public synchronized void setRegisters(InputRegister[] regs) { - if (regs == null) { - registers = null; - count = 0; - return; - } - - registers = Arrays.copyOf(regs, regs.length); - if (regs.length > 31) { - throw new IllegalArgumentException(); - } - - count = regs.length; - } - - public int getRegister(int index) { - return registers[index].getValue(); - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a header, - * such as for Modbus/TCP, it will have been read already. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - - /* - * Read and discard the byte count. There's no way to indicate - * the packet was inconsistent, other than throwing an I/O - * exception for an invalid packet format ... - */ - din.readShort(); - - // The first register is the number of registers which - // follow. Save that as count, not as a register. - count = din.readUnsignedShort(); - registers = new InputRegister[count]; - - for (int i = 0; i < count; i++) { - registers[i] = new SimpleInputRegister(din.readShort()); - } - } - - /** - * getMessage -- format the message into a byte array. - * @return Byte array of message - */ - public byte[] getMessage() { - byte result[] = new byte[count * 2 + 4]; - - int len = count * 2 + 2; - result[0] = (byte)(len >> 8); - result[1] = (byte)(len & 0xFF); - result[2] = (byte)(count >> 8); - result[3] = (byte)(count & 0xFF); - - for (int i = 0; i < count; i++) { - byte value[] = registers[i].toBytes(); - result[i * 2 + 4] = value[0]; - result[i * 2 + 5] = value[1]; - } - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordRequest.java deleted file mode 100644 index a0c646c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordRequest.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.msg.ReadFileRecordResponse.RecordResponse; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.*; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read File Record request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadFileRecordRequest extends ModbusRequest { - private RecordRequest[] records; - - /** - * Constructs a new Read File Record request instance. - */ - public ReadFileRecordRequest() { - super(); - - setFunctionCode(Modbus.READ_FILE_RECORD); - - // Request size byte is all that is required. - setDataLength(1); - } - - /** - * getRequestSize -- return the total request size. This is useful for - * determining if a new record can be added. - * - * @return size in bytes of response. - */ - public int getRequestSize() { - if (records == null) { - return 1; - } - - int size = 1; - for (RecordRequest record : records) { - size += record.getRequestSize(); - } - - return size; - } - - /** - * getRequestCount - * @return the number of record requests in this message - */ - public int getRequestCount() { - if (records == null) { - return 0; - } - - return records.length; - } - - /** - * getRecord - * @param index Reference - * @return the record request indicated by the reference - */ - public RecordRequest getRecord(int index) { - return records[index]; - } - - /** - * addRequest -- add a new record request. - * @param request Record request to add - */ - public void addRequest(RecordRequest request) { - if (request.getRequestSize() + getRequestSize() > 248) { - throw new IllegalArgumentException(); - } - - if (records == null) { - records = new RecordRequest[1]; - } - else { - RecordRequest old[] = records; - records = new RecordRequest[old.length + 1]; - - System.arraycopy(old, 0, records, 0, old.length); - } - records[records.length - 1] = request; - - setDataLength(getRequestSize()); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadFileRecordResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadFileRecordResponse response = (ReadFileRecordResponse)getResponse(); - - // Get the process image. - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - // There is a list of requests to be resolved. - try { - for (int i = 0; i < getRequestCount(); i++) { - RecordRequest recordRequest = getRecord(i); - if (recordRequest.getFileNumber() < 0 || recordRequest.getFileNumber() >= procimg.getFileCount()) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - File file = procimg.getFileByNumber(recordRequest.getFileNumber()); - - if (recordRequest.getRecordNumber() < 0 || recordRequest.getRecordNumber() >= file.getRecordCount()) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - Record record = file.getRecord(recordRequest.getRecordNumber()); - int registers = recordRequest.getWordCount(); - if (record == null && registers != 0) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - short data[] = new short[registers]; - for (int j = 0; j < registers; j++) { - Register register = record.getRegister(j); - if (register == null) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - data[j] = register.toShort(); - } - RecordResponse recordResponse = new RecordResponse(data); - response.addResponse(recordResponse); - } - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - return response; - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- read all the data for this request. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - int byteCount = din.readUnsignedByte(); - - int recordCount = byteCount / 7; - records = new RecordRequest[recordCount]; - - for (int i = 0; i < recordCount; i++) { - if (din.readByte() != 6) { - throw new IOException(); - } - - int file = din.readUnsignedShort(); - int record = din.readUnsignedShort(); - if (record < 0 || record >= 10000) { - throw new IOException(); - } - - int count = din.readUnsignedShort(); - - records[i] = new RecordRequest(file, record, count); - } - } - - /** - * getMessage - * @return the PDU message - */ - public byte[] getMessage() { - byte request[] = new byte[1 + 7 * records.length]; - - int offset = 0; - request[offset++] = (byte)(request.length - 1); - - for (RecordRequest record : records) { - record.getRequest(request, offset); - offset += 7; - } - return request; - } - - public static class RecordRequest { - private int fileNumber; - private int recordNumber; - private int wordCount; - - public RecordRequest(int file, int record, int count) { - fileNumber = file; - recordNumber = record; - wordCount = count; - } - - public int getFileNumber() { - return fileNumber; - } - - public int getRecordNumber() { - return recordNumber; - } - - public int getWordCount() { - return wordCount; - } - - /** - * getRequestSize - * @return the size of the response in bytes - */ - public int getRequestSize() { - return 7 + wordCount * 2; - } - - public void getRequest(byte[] request, int offset) { - request[offset] = 6; - request[offset + 1] = (byte)(fileNumber >> 8); - request[offset + 2] = (byte)(fileNumber & 0xFF); - request[offset + 3] = (byte)(recordNumber >> 8); - request[offset + 4] = (byte)(recordNumber & 0xFF); - request[offset + 5] = (byte)(wordCount >> 8); - request[offset + 6] = (byte)(wordCount & 0xFF); - } - - public byte[] getRequest() { - byte[] request = new byte[7]; - - getRequest(request, 0); - - return request; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordResponse.java deleted file mode 100644 index 9dc9054..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadFileRecordResponse.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadFileRecordResponse. - * - * @author Julie (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadFileRecordResponse extends ModbusResponse { - - private RecordResponse[] records = null; - - /** - * Constructs a new ReadFileRecordResponse instance. - */ - public ReadFileRecordResponse() { - super(); - - setFunctionCode(Modbus.READ_FILE_RECORD); - } - - /** - * Returns the number of bytes needed for the response. - * - * The response is 1 byte for the total response size, plus - * the sum of the sizes of all the records in the response. - * - * @return the number of bytes in the response. - */ - public int getByteCount() { - if (records == null) { - return 1; - } - - int size = 1; - for (RecordResponse record : records) { - size += record.getResponseSize(); - } - - return size; - } - - /** - * getRecordCount -- return the number of records in the response. - * - * @return count of records in response. - */ - public int getRecordCount() { - if (records == null) { - return 0; - } - - return records.length; - } - - /** - * getRecord - * @param index Record to get - * @return the record response indicated by the reference - */ - public RecordResponse getRecord(int index) { - return records[index]; - } - - /** - * addResponse -- add a new record response. - * @param response Record response to add - */ - public void addResponse(RecordResponse response) { - if (records == null) { - records = new RecordResponse[1]; - } - else { - RecordResponse old[] = records; - records = new RecordResponse[old.length + 1]; - - System.arraycopy(old, 0, records, 0, old.length); - } - records[records.length - 1] = response; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(getByteCount() - 1); - - if (records == null) { - return; - } - - for (RecordResponse record : records) { - dout.write(record.getResponse()); - } - } - - public void readData(DataInput din) throws IOException { - int byteCount = (din.readUnsignedByte() & 0xFF); - - int remainder = byteCount; - while (remainder > 0) { - int length = din.readUnsignedByte(); - remainder--; - - int function = din.readByte(); - remainder--; - - if (function != 6 || (length - 1) > remainder) { - throw new IOException("Invalid response format"); - } - short[] data = new short[(length - 1) / 2]; - for (int i = 0; i < data.length; i++) { - data[i] = din.readShort(); - remainder -= 2; - } - RecordResponse response = new RecordResponse(data); - addResponse(response); - } - setDataLength(byteCount + 1); - } - - public byte[] getMessage() { - byte result[]; - - result = new byte[getByteCount()]; - - int offset = 0; - result[offset++] = (byte)(result.length - 1); - - for (RecordResponse record : records) { - record.getResponse(result, offset); - offset += record.getWordCount() * 2; - } - return result; - } - - public static class RecordResponse { - private int wordCount; - private byte[] data; - - public RecordResponse(short data[]) { - wordCount = data.length; - this.data = new byte[wordCount * 2]; - - int offset = 0; - for (int i = 0; i < wordCount; i++) { - this.data[offset++] = (byte)(data[i] >> 8); - this.data[offset++] = (byte)(data[i] & 0xFF); - } - } - - public int getWordCount() { - return wordCount; - } - - public SimpleRegister getRegister(int register) { - if (register < 0 || register >= wordCount) { - throw new IndexOutOfBoundsException("0 <= " + register + " < " + wordCount); - } - byte b1 = data[register * 2]; - byte b2 = data[register * 2 + 1]; - - return new SimpleRegister(b1, b2); - } - - /** - * getResponseSize -- return the size of the response in bytes. - * - * The response is a byte count, a function code, then wordCount - * words (2 bytes). - * @return the size of the response in bytes - */ - public int getResponseSize() { - return 2 + (wordCount * 2); - } - - /** - * getResponse - return the response data for this record - * - * The response data is the byte size of the response, minus this - * byte, the function code (6), then the raw byte data for the - * registers (wordCount * 2 bytes). - * - * @param request Request message - * @param offset Offset into buffer - */ - public void getResponse(byte[] request, int offset) { - request[offset] = (byte)(1 + (wordCount * 2)); - request[offset + 1] = 6; - System.arraycopy(data, 0, request, offset + 2, data.length); - } - - public byte[] getResponse() { - byte[] request = new byte[getResponseSize()]; - getResponse(request, 0); - return request; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesRequest.java deleted file mode 100644 index 8258e54..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesRequest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.DigitalIn; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadInputDiscretesRequest. The implementation - * directly correlates with the class 1 function read input discretes (FC - * 2). It encapsulates the corresponding request message. - *

- * Input Discretes are understood as bits that cannot be manipulated (i.e. set - * or unset). - * - * @author Dieter Wimberger - * @author jfhaugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadInputDiscretesRequest extends ModbusRequest { - - // instance attributes - private int reference; - private int bitCount; - - /** - * Constructs a new ReadInputDiscretesRequest instance. - */ - public ReadInputDiscretesRequest() { - super(); - - setFunctionCode(Modbus.READ_INPUT_DISCRETES); - - // Two bytes for count, two bytes for offset. - setDataLength(4); - } - - /** - * Constructs a new ReadInputDiscretesRequest instance with a given - * reference and count of input discretes (i.e. bits) to be read. - *

- * - * @param ref the reference number of the register to read from. - * @param count the number of bits to be read. - */ - public ReadInputDiscretesRequest(int ref, int count) { - super(); - - setFunctionCode(Modbus.READ_INPUT_DISCRETES); - // 4 bytes (unit id and function code is excluded) - setDataLength(4); - setReference(ref); - setBitCount(count); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadInputDiscretesResponse(getBitCount())); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadInputDiscretesResponse response; - DigitalIn[] dins; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get input discretes range - try { - dins = procimg.getDigitalInRange(getReference(), getBitCount()); - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (ReadInputDiscretesResponse)getResponse(); - - // Populate the discrete values from the process image. - for (int i = 0; i < dins.length; i++) { - response.setDiscreteStatus(i, dins[i].isSet()); - } - - return response; - } - - /** - * Returns the reference of the discrete to to start reading from with - * this ReadInputDiscretesRequest. - * - * @return the reference of the discrete to start reading from as - * int. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to start reading from with this - * ReadInputDiscretesRequest. - *

- * - * @param ref the reference of the register to start reading from. - */ - public void setReference(int ref) { - if (ref < 0 || bitCount + ref >= 65536) { - throw new IllegalArgumentException(); - } - - reference = ref; - } - - /** - * Returns the number of bits (i.e. input discretes) to be read with this - * ReadInputDiscretesRequest. - *

- * - * @return the number of bits to be read. - */ - public int getBitCount() { - return bitCount; - } - - /** - * Sets the number of bits (i.e. input discretes) to be read with this - * ReadInputDiscretesRequest. - * - * @param count the number of bits to be read. - */ - public void setBitCount(int count) { - if (count < 0 || count > 2000 || count + reference >= 65536) { - throw new IllegalArgumentException(); - } - - bitCount = count; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - dout.writeShort(bitCount); - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - bitCount = din.readUnsignedShort(); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)((reference & 0xff)); - result[2] = (byte)((bitCount >> 8) & 0xff); - result[3] = (byte)((bitCount & 0xff)); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesResponse.java deleted file mode 100644 index c6cc891..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputDiscretesResponse.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.util.BitVector; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadInputDiscretesResponse. - * The implementation directly correlates with the class 1 - * function read input discretes (FC 2). It encapsulates - * the corresponding response message. - *

- * Input Discretes are understood as bits that cannot be - * manipulated (i.e. set or unset). - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadInputDiscretesResponse - extends ModbusResponse { - - //instance attributes - private int bitCount; - private BitVector discretes; - - /** - * Constructs a new ReadInputDiscretesResponse - * instance. - */ - public ReadInputDiscretesResponse() { - super(); - setFunctionCode(Modbus.READ_INPUT_DISCRETES); - } - - /** - * Constructs a new ReadInputDiscretesResponse - * instance with a given count of input discretes - * (i.e. bits). - * - * @param count the number of bits to be read. - */ - public ReadInputDiscretesResponse(int count) { - super(); - setFunctionCode(Modbus.READ_INPUT_DISCRETES); - setBitCount(count); - } - - /** - * Returns the number of bits (i.e. input discretes) - * read with the request. - * - * @return the number of bits that have been read. - */ - public int getBitCount() { - return bitCount; - } - - /** - * Sets the number of bits in this response. - * - * @param count the number of response bits as int. - */ - public void setBitCount(int count) { - bitCount = count; - discretes = new BitVector(count); - //set correct length, without counting unitid and fc - setDataLength(discretes.byteSize() + 1); - } - - /** - * Returns the BitVector that stores - * the collection of bits that have been read. - *

- * - * @return the BitVector holding the - * bits that have been read. - */ - public BitVector getDiscretes() { - return discretes; - } - - /** - * Convenience method that returns the state - * of the bit at the given index. - *

- * - * @param index the index of the input discrete - * for which the status should be returned. - * - * @return true if set, false otherwise. - * - * @throws IndexOutOfBoundsException if the - * index is out of bounds - */ - public boolean getDiscreteStatus(int index) throws IndexOutOfBoundsException { - - return discretes.getBit(index); - } - - /** - * Sets the status of the given input discrete. - * - * @param index the index of the input discrete to be set. - * @param b true if to be set, false if to be reset. - * - * @throws IndexOutOfBoundsException if the given index exceeds bounds. - */ - public void setDiscreteStatus(int index, boolean b) throws IndexOutOfBoundsException { - discretes.setBit(index, b); - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(discretes.byteSize()); - dout.write(discretes.getBytes(), 0, discretes.byteSize()); - } - - public void readData(DataInput din) throws IOException { - - int count = din.readUnsignedByte(); - byte[] data = new byte[count]; - for (int k = 0; k < count; k++) { - data[k] = din.readByte(); - } - - //decode bytes into bitvector - discretes = BitVector.createBitVector(data); - if (discretes != null) { - bitCount = discretes.size(); - } - - //update data length - setDataLength(count + 1); - } - - public byte[] getMessage() { - byte result[]; - int len = 1 + discretes.byteSize(); - - result = new byte[len]; - result[0] = (byte)discretes.byteSize(); - System.arraycopy(discretes.getBytes(), 0, result, 1, discretes.byteSize()); - - return result; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersRequest.java deleted file mode 100644 index ea13c81..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersRequest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadInputRegistersRequest. The implementation - * directly correlates with the class 0 function read multiple registers (FC - * 4). It encapsulates the corresponding request message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadInputRegistersRequest extends ModbusRequest { - - // instance attributes - private int reference; - private int wordCount; - - /** - * Constructs a new ReadInputRegistersRequest instance. - */ - public ReadInputRegistersRequest() { - super(); - - setFunctionCode(Modbus.READ_INPUT_REGISTERS); - // 4 bytes (unit id and function code is excluded) - setDataLength(4); - } - - /** - * Constructs a new ReadInputRegistersRequest instance with a given - * reference and count of words to be read. - *

- * - * @param ref the reference number of the register to read from. - * @param count the number of words to be read. - */ - public ReadInputRegistersRequest(int ref, int count) { - super(); - - setFunctionCode(Modbus.READ_INPUT_REGISTERS); - // 4 bytes (unit id and function code is excluded) - setDataLength(4); - - setReference(ref); - setWordCount(count); - } - - public ReadInputRegistersResponse getResponse() { - ReadInputRegistersResponse response = (ReadInputRegistersResponse)updateResponseWithHeader(new ReadInputRegistersResponse()); - response.setWordCount(getWordCount()); - return response; - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadInputRegistersResponse response; - InputRegister[] inpregs; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get input registers range - try { - inpregs = procimg.getInputRegisterRange(getReference(), getWordCount()); - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = getResponse(); - response.setRegisters(inpregs); - - return response; - } - - /** - * Returns the reference of the register to to start reading from with this - * ReadInputRegistersRequest. - *

- * - * @return the reference of the register to start reading from as - * int. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to start reading from with this - * ReadInputRegistersRequest. - *

- * - * @param ref the reference of the register to start reading from. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the number of words to be read with this - * ReadInputRegistersRequest. - *

- * - * @return the number of words to be read as int. - */ - public int getWordCount() { - return wordCount; - } - - /** - * Sets the number of words to be read with this - * ReadInputRegistersRequest. - *

- * - * @param count the number of words to be read. - */ - public void setWordCount(int count) { - wordCount = count; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - dout.writeShort(wordCount); - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - wordCount = din.readUnsignedShort(); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((wordCount >> 8) & 0xff); - result[3] = (byte)(wordCount & 0xff); - - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersResponse.java deleted file mode 100644 index 98549ec..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadInputRegistersResponse.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.SimpleInputRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a ReadInputRegistersRequest. The implementation - * directly correlates with the class 0 function read multiple registers (FC - * 4). It encapsulates the corresponding response message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadInputRegistersResponse extends ModbusResponse { - - // instance attributes - private int byteCount; - private InputRegister[] registers; - - /** - * Constructs a new ReadInputRegistersResponse instance. - */ - public ReadInputRegistersResponse() { - super(); - - setFunctionCode(Modbus.READ_INPUT_REGISTERS); - } - - /** - * Constructs a new ReadInputRegistersResponse instance. - * - * @param registers the InputRegister[] holding response input registers. - */ - public ReadInputRegistersResponse(InputRegister[] registers) { - super(); - - setFunctionCode(Modbus.READ_INPUT_REGISTERS); - setDataLength(registers == null ? 0 : (registers.length * 2 + 1)); - - this.registers = registers == null ? null : Arrays.copyOf(registers, registers.length); - byteCount = registers == null ? 0 : (registers.length * 2); - } - - /** - * Returns the number of bytes that have been read. - * - * @return the number of bytes that have been read as int. - */ - public int getByteCount() { - return byteCount; - } - - /** - * Returns the number of words that have been read. The returned value - * should be half as much as the byte count of the response. - * - * @return the number of words that have been read as int. - */ - public int getWordCount() { - return byteCount / 2; - } - - /** - * Set the number of words to be written. - * @param count Number of words in response - */ - public void setWordCount(int count) { - byteCount = count * 2; - } - - /** - * Returns the InputRegister at the given position (relative to the - * reference used in the request). - * - * @param index the relative index of the InputRegister. - * - * @return the register as InputRegister. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public InputRegister getRegister(int index) throws IndexOutOfBoundsException { - if (index < 0) { - throw new IndexOutOfBoundsException(index + " < 0"); - } - - if (index >= getWordCount()) { - throw new IndexOutOfBoundsException(index + " >= " + getWordCount()); - } - - return registers[index]; - } - - /** - * Returns the value of the register at the given position (relative to the - * reference used in the request) interpreted as usigned short. - * - * @param index the relative index of the register for which the value should - * be retrieved. - * - * @return the unsigned short value as an int. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public int getRegisterValue(int index) throws IndexOutOfBoundsException { - return getRegister(index).toUnsignedShort(); - } - - /** - * Returns a reference to the array of input registers read. - * - * @return a InputRegister[] instance. - */ - public synchronized InputRegister[] getRegisters() { - InputRegister[] dest = new InputRegister[registers.length]; - System.arraycopy(registers, 0, dest, 0, dest.length); - return dest; - } - - /** - * Sets the entire block of registers for this response - * @param registers Array of registers - */ - public void setRegisters(InputRegister[] registers) { - setDataLength(registers == null ? 0 : (registers.length * 2 + 1)); - this.registers = registers == null ? null : Arrays.copyOf(registers, registers.length); - byteCount = registers == null ? 0 : (registers.length * 2); - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(byteCount); - - for (int k = 0; k < getWordCount(); k++) { - dout.write(registers[k].toBytes()); - } - } - - public void readData(DataInput din) throws IOException { - byteCount = din.readUnsignedByte(); - - InputRegister[] registers = new InputRegister[getWordCount()]; - for (int k = 0; k < getWordCount(); k++) { - registers[k] = new SimpleInputRegister(din.readByte(), din.readByte()); - } - this.registers = registers; - - setDataLength(byteCount); - } - - public byte[] getMessage() { - byte result[] = new byte[registers.length * 2 + 1]; - result[0] = (byte)(registers.length * 2); - - for (int i = 0; i < registers.length; i++) { - byte value[] = registers[i].toBytes(); - - result[1 + i * 2] = value[0]; - result[2 + i * 2] = value[1]; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIRequest.java deleted file mode 100644 index a40ea14..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIRequest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.EOFException; -import java.io.IOException; - -/** - * Class implementing a Read MEI Data request. - * - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadMEIRequest extends ModbusRequest { - - // instance attributes - private int subCode; - private int fieldLevel; - private int fieldId; - - /** - * Constructs a new Read MEI Data request instance. - */ - public ReadMEIRequest() { - super(); - - setFunctionCode(Modbus.READ_MEI); - subCode = 0x0E; - - // 3 bytes (unit id and function code is excluded) - setDataLength(3); - } - - /** - * Constructs a new Read MEI Data request instance with a given - * reference and count of coils (i.e. bits) to be read. - *

- * - * @param level the reference number of the register to read from. - * @param id the number of bits to be read. - */ - public ReadMEIRequest(int level, int id) { - super(); - - setFunctionCode(Modbus.READ_MEI); - subCode = 0x0E; - - // 3 bytes (unit id and function code is excluded) - setDataLength(3); - setLevel(level); - setFieldId(id); - } - - @Override - public ModbusResponse getResponse() { - - // Any other sub-function is an error. - if (getSubCode() != 0x0E) { - IllegalFunctionExceptionResponse error = new IllegalFunctionExceptionResponse(); - return updateResponseWithHeader(error); - } - return updateResponseWithHeader(new ReadMEIResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * Gets the MEI subcode associated with this request. - * @return The MEI sub code - */ - public int getSubCode() { - return subCode; - } - - /** - * Returns the reference of the register to to start reading from with this - * ReadCoilsRequest. - *

- * - * @return the reference of the register to start reading from as - * int. - */ - public int getLevel() { - return fieldLevel; - } - - /** - * Sets the reference of the register to start reading from with this - * ReadCoilsRequest. - *

- * - * @param level the reference of the register to start reading from. - */ - public void setLevel(int level) { - fieldLevel = level; - } - - /** - * Returns the number of bits (i.e. coils) to be read with this - * ReadCoilsRequest. - *

- * - * @return the number of bits to be read. - */ - public int getFieldId() { - return fieldId; - } - - /** - * Sets the number of bits (i.e. coils) to be read with this - * ReadCoilsRequest. - *

- * - * @param id the number of bits to be read. - */ - public void setFieldId(int id) { - fieldId = id; - } - - public void writeData(DataOutput dout) throws IOException { - byte results[] = new byte[3]; - - results[0] = (byte)subCode; - results[1] = (byte)fieldLevel; - results[2] = (byte)fieldId; - - dout.write(results); - } - - public void readData(DataInput din) throws IOException { - subCode = din.readUnsignedByte(); - - if (subCode != 0xE) { - try { - while (din.readByte() >= 0) { - } - } - catch (EOFException x) { - // do nothing. - } - return; - } - fieldLevel = din.readUnsignedByte(); - fieldId = din.readUnsignedByte(); - } - - public byte[] getMessage() { - byte results[] = new byte[3]; - - results[0] = (byte)subCode; - results[1] = (byte)fieldLevel; - results[2] = (byte)fieldId; - - return results; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIResponse.java deleted file mode 100644 index 99e9556..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMEIResponse.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadMEIResponse. - * - * Derived from similar class for Read Coils response. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadMEIResponse extends ModbusResponse { - - private static final Logger logger = LoggerFactory.getLogger(ReadMEIResponse.class); - - //instance attributes - private int fieldLevel = 0; - private int conformity = 1; - private int fieldCount = 0; - private String fields[] = new String[64]; - private int fieldIds[] = new int[64]; - private boolean moreFollows = false; - private int nextFieldId; - - /** - * Constructs a new ReadMEIResponse - * instance. - */ - public ReadMEIResponse() { - super(); - setFunctionCode(Modbus.READ_MEI); - } - - /** - * Returns the number of fields - * read with the request. - *

- * - * @return the number of fields that have been read. - */ - public int getFieldCount() { - if (fields == null) { - return 0; - } - else { - return fields.length; - } - } - - /** - * Returns the array of strings that were read - * @return Array of the fields read - */ - public synchronized String[] getFields() { - String[] dest = new String[fields.length]; - System.arraycopy(fields, 0, dest, 0, dest.length); - return dest; - } - - /** - * Convenience method that returns the field - * at the requested index - *

- * - * @param index the index of the field which - * should be returned. - * - * @return requested field - * - * @throws IndexOutOfBoundsException if the - * index is out of bounds - */ - public String getField(int index) throws IndexOutOfBoundsException { - return fields[index]; - } - - /** - * Convenience method that returns the field - * ID at the given index. - *

- * - * @param index the index of the field for which - * the ID should be returned. - * - * @return field ID - * - * @throws IndexOutOfBoundsException if the - * index is out of bounds - */ - public int getFieldId(int index) throws IndexOutOfBoundsException { - return fieldIds[index]; - } - - public void setFieldLevel(int level) { - fieldLevel = level; - } - - public void addField(int id, String text) { - fieldIds[fieldCount] = id; - fields[fieldCount] = text; - fieldCount++; - } - - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - public void readData(DataInput din) throws IOException { - int byteCount; - - int subCode = din.readUnsignedByte(); - if (subCode != 0xE) { - throw new IOException("Invalid sub code"); - } - - fieldLevel = din.readUnsignedByte(); - conformity = din.readUnsignedByte(); - moreFollows = din.readUnsignedByte() == 0xFF; - nextFieldId = din.readUnsignedByte(); - - fieldCount = din.readUnsignedByte(); - - byteCount = 6; - - if (fieldCount > 0) { - fields = new String[fieldCount]; - fieldIds = new int[fieldCount]; - - for (int i = 0; i < fieldCount; i++) { - fieldIds[i] = din.readUnsignedByte(); - int len = din.readUnsignedByte(); - byte data[] = new byte[len]; - din.readFully(data); - fields[i] = new String(data, "UTF-8"); - - byteCount += 2 + len; - } - setDataLength(byteCount); - } - else { - setDataLength(byteCount); - } - } - - public byte[] getMessage() { - int size = 6; - - for (int i = 0; i < fieldCount; i++) { - // Add the field ID - size++; - - // Add the string length byte and the - // actual string length. - size++; - size += fields[i].length(); - } - - byte result[] = new byte[size]; - int offset = 0; - - result[offset++] = 0x0E; - result[offset++] = (byte)fieldLevel; - result[offset++] = (byte)conformity; - result[offset++] = (byte)(moreFollows ? 0xFF : 0); - result[offset++] = (byte)nextFieldId; - result[offset++] = (byte)fieldCount; - - for (int i = 0; i < fieldCount; i++) { - result[offset++] = (byte)fieldIds[i]; - result[offset++] = (byte)fields[i].length(); - try { - System.arraycopy(fields[i].getBytes("US-ASCII"), 0, result, offset, fields[i].length()); - } - catch (Exception e) { - logger.debug("Problem converting bytes to string - {}", e.getMessage()); - } - offset += fields[i].length(); - } - return result; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersRequest.java deleted file mode 100644 index a34e3d0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersRequest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.procimg.Register; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadMultipleRegistersRequest. The - * implementation directly correlates with the class 0 function read multiple - * registers (FC 3). It encapsulates the corresponding request message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadMultipleRegistersRequest extends ModbusRequest { - - // instance attributes - private int reference; - private int wordCount; - - /** - * Constructs a new ReadMultipleRegistersRequest instance. - */ - public ReadMultipleRegistersRequest() { - super(); - - setFunctionCode(Modbus.READ_MULTIPLE_REGISTERS); - setDataLength(4); - } - - /** - * Constructs a new ReadMultipleRegistersRequest instance with a - * given reference and count of words to be read. This message reads - * from holding (r/w) registers. - * - * @param ref the reference number of the register to read from. - * @param count the number of words to be read. - * - * @see ReadInputRegistersRequest - */ - public ReadMultipleRegistersRequest(int ref, int count) { - super(); - - setFunctionCode(Modbus.READ_MULTIPLE_REGISTERS); - setDataLength(4); - - setReference(ref); - setWordCount(count); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadMultipleRegistersResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadMultipleRegistersResponse response; - Register[] regs; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get input registers range - try { - regs = procimg.getRegisterRange(getReference(), getWordCount()); - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (ReadMultipleRegistersResponse)getResponse(); - response.setRegisters(regs); - - return response; - } - - /** - * Returns the reference of the register to to start reading from with this - * ReadMultipleRegistersRequest. - *

- * - * @return the reference of the register to start reading from as - * int. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to start reading from with this - * ReadMultipleRegistersRequest. - *

- * - * @param ref the reference of the register to start reading from. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the number of words to be read with this - * ReadMultipleRegistersRequest. - *

- * - * @return the number of words to be read as int. - */ - public int getWordCount() { - return wordCount; - } - - /** - * Sets the number of words to be read with this - * ReadMultipleRegistersRequest. - *

- * - * @param count the number of words to be read. - */ - public void setWordCount(int count) { - wordCount = count; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - dout.writeShort(wordCount); - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - wordCount = din.readUnsignedShort(); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((wordCount >> 8) & 0xff); - result[3] = (byte)(wordCount & 0xff); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersResponse.java deleted file mode 100644 index a84ebae..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadMultipleRegistersResponse.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a ReadMultipleRegistersResponse. The - * implementation directly correlates with the class 0 function read multiple - * registers (FC 3). It encapsulates the corresponding response message. - * - * @author Dieter Wimberger - * @author Julie (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadMultipleRegistersResponse extends ModbusResponse { - - // instance attributes - private int byteCount; - private Register[] registers; - - /** - * Constructs a new ReadMultipleRegistersResponse instance. - */ - public ReadMultipleRegistersResponse() { - super(); - setFunctionCode(Modbus.READ_MULTIPLE_REGISTERS); - } - - /** - * Constructs a new ReadInputRegistersResponse instance. - * - * @param registers the Register[] holding response registers. - */ - public ReadMultipleRegistersResponse(Register[] registers) { - super(); - - setFunctionCode(Modbus.READ_MULTIPLE_REGISTERS); - setDataLength(registers == null ? 0 : (registers.length * 2 + 1)); - - this.registers = registers == null ? null : Arrays.copyOf(registers, registers.length); - byteCount = registers == null ? 0 : (registers.length * 2); - } - - /** - * Returns the number of bytes that have been read. - * - * @return the number of bytes that have been read as int. - */ - public int getByteCount() { - return byteCount; - } - - /** - * Returns the number of words that have been read. The returned value - * should be half of the the byte count of this - * ReadMultipleRegistersResponse. - * - * @return the number of words that have been read as int. - */ - public int getWordCount() { - return byteCount / 2; - } - - /** - * Returns the Register at the given position (relative to the - * reference used in the request). - * - * @param index the relative index of the Register. - * - * @return the register as Register. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public Register getRegister(int index) { - if (registers == null) { - throw new IndexOutOfBoundsException("No registers defined!"); - } - - if (index < 0) { - throw new IndexOutOfBoundsException("Negative index: " + index); - } - - if (index >= getWordCount()) { - throw new IndexOutOfBoundsException(index + " > " + getWordCount()); - } - - return registers[index]; - } - - /** - * Returns the value of the register at the given position (relative to the - * reference used in the request) interpreted as unsigned short. - * - * @param index the relative index of the register for which the value should - * be retrieved. - * - * @return the value as int. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public int getRegisterValue(int index) throws IndexOutOfBoundsException { - return getRegister(index).toUnsignedShort(); - } - - /** - * Returns the reference to the array of registers read. - * - * @return a Register[] instance. - */ - public synchronized Register[] getRegisters() { - Register[] dest = new Register[registers.length]; - System.arraycopy(registers, 0, dest, 0, dest.length); - return dest; - } - - /** - * Sets the entire block of registers for this response - * @param registers Array of registers to use - */ - public void setRegisters(Register[] registers) { - byteCount = registers == null ? 0 : registers.length * 2; - this.registers = registers == null ? null : Arrays.copyOf(registers, registers.length); - setDataLength(byteCount + 1); - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(byteCount); - - for (int k = 0; k < getWordCount(); k++) { - dout.write(registers[k].toBytes()); - } - } - - public void readData(DataInput din) throws IOException { - byteCount = din.readUnsignedByte(); - - registers = new Register[getWordCount()]; - - for (int k = 0; k < getWordCount(); k++) { - registers[k] = new SimpleRegister(din.readByte(), din.readByte()); - } - - setDataLength(byteCount + 1); - } - - public byte[] getMessage() { - byte result[]; - - result = new byte[getWordCount() * 2 + 1]; - - int offset = 0; - result[offset++] = (byte)byteCount; - - for (Register register : registers) { - byte[] data = register.toBytes(); - - result[offset++] = data[0]; - result[offset++] = data[1]; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsRequest.java deleted file mode 100644 index 8b05d75..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsRequest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadSerialDiagnosticsRequest. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadSerialDiagnosticsRequest extends ModbusRequest { - - // Message fields. - private int function; - private short data; - - /** - * Constructs a new Diagnostics request - * instance. - */ - public ReadSerialDiagnosticsRequest() { - super(); - - setFunctionCode(Modbus.READ_SERIAL_DIAGNOSTICS); - setDataLength(4); - } - - /** - * getFunction -- Get the DIAGNOSTICS sub-function. - * - * @return int - */ - public int getFunction() { - return function; - } - - /** - * setFunction - Set the DIAGNOSTICS sub-function. - * - * @param function - DIAGNOSTICS command sub-function. - */ - public void setFunction(int function) { - this.function = function; - data = 0; - } - - /** - * getWordCount -- get the number of words in data. - * @return Number of words in the data - */ - public int getWordCount() { - return 1; - } - - /** - * getData - * @return the first data item - */ - public int getData() { - return data; - } - - /** - * setData -- Set the optional data value - * @param value Diagnostics value - */ - public void setData(int value) { - data = (short)value; - } - - /** - * getData -- Get the data item at the index. - * - * @param index - Unused, must be 0. - * @return Data at index 0 - * - * @deprecated - */ - public int getData(int index) { - if (index != 0) { - throw new IndexOutOfBoundsException(); - } - return data; - } - - /** - * setData -- Set the data item at the index - * - * @param index - Unused, must be 0. - * @param value - Optional data value for function. - * - * @deprecated - */ - public void setData(int index, int value) { - if (index != 0) { - throw new IndexOutOfBoundsException(); - } - data = (short)value; - } - - @Override - public ModbusResponse getResponse() { - ReadSerialDiagnosticsResponse response = new ReadSerialDiagnosticsResponse(); - - // Copy the sub-function code. - response.setFunction(getFunction()); - - return updateResponseWithHeader(response); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- Read the function code and data value - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - function = din.readUnsignedShort(); - data = (short)(din.readShort() & 0xFFFF); - } - - /** - * getMessage -- Create the DIAGNOSTICS message paylaod. - * @return Response as byte array - */ - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)(function >> 8); - result[1] = (byte)(function & 0xFF); - result[2] = (byte)(data >> 8); - result[3] = (byte)(data & 0xFF); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsResponse.java deleted file mode 100644 index 9d2bb8d..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadSerialDiagnosticsResponse.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadSerialDiagnosticsResponse. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadSerialDiagnosticsResponse extends ModbusResponse { - - // Message fields. - private int function; - private short data; - - /** - * Constructs a new Diagnostics response - * instance. - */ - public ReadSerialDiagnosticsResponse() { - super(); - - setFunctionCode(Modbus.READ_SERIAL_DIAGNOSTICS); - setDataLength(4); - } - - /** - * getFunction -- Get the DIAGNOSTICS sub-function. - * - * @return Function code - */ - public int getFunction() { - return function; - } - - /** - * setFunction - Set the DIAGNOSTICS sub-function. - * - * @param function - DIAGNOSTICS command sub-function. - */ - public void setFunction(int function) { - this.function = function; - data = 0; - } - - /** - * getWordCount -- get the number of words in data. - * @return Number of words in the data - */ - public int getWordCount() { - return 1; - } - - /** - * getData - * @return the first data item - */ - public int getData() { - return data; - } - - /** - * setData -- Set the optional data value - * @param value optional data value - */ - public void setData(int value) { - data = (short)value; - } - - /** - * getData -- Get the data item at the index. - * - * @param index - Unused, must be 0. - * @return Data at index 0 - * - * @deprecated - */ - public int getData(int index) { - if (index != 0) { - throw new IndexOutOfBoundsException(); - } - - return data; - } - - /** - * setData -- Set the data item at the index - * - * @param index - Unused, must be 0. - * @param value - Optional data value for function. - * - * @deprecated - */ - public void setData(int index, int value) { - if (index != 0) { - throw new IndexOutOfBoundsException(); - } - - data = (short)value; - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- Read the function code and data value - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - function = din.readUnsignedShort(); - data = (short)(din.readShort() & 0xFFFF); - } - - /** - * getMessage -- Create the DIAGNOSTICS message paylaod. - * @return message paylaod - */ - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)(function >> 8); - result[1] = (byte)(function & 0xFF); - result[2] = (byte)(data >> 8); - result[3] = (byte)(data & 0xFF); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleRequest.java deleted file mode 100644 index 98b0e23..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleRequest.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.NonWordDataHandler; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.*; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a Read / Write Multiple Registers request. - * - * @author Julie Haugh - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadWriteMultipleRequest extends ModbusRequest { - private NonWordDataHandler nonWordDataHandler; - private int readReference; - private int readCount; - private int writeReference; - private int writeCount; - private Register registers[]; - - /** - * Constructs a new Read/Write Multiple Registers Request instance. - * @param unit Unit ID - * @param readRef Register to read - * @param writeCount Number of registers to write - * @param writeRef Starting register to write - * @param readCount Number of registers to read - */ - public ReadWriteMultipleRequest(int unit, int readRef, int readCount, int writeRef, int writeCount) { - super(); - - setUnitID(unit); - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - - // There is no additional data in this request. - setDataLength(9 + writeCount * 2); - - readReference = readRef; - this.readCount = readCount; - writeReference = writeRef; - this.writeCount = writeCount; - registers = new Register[writeCount]; - for (int i = 0; i < writeCount; i++) { - registers[i] = new SimpleRegister(0); - } - } - - /** - * Constructs a new Read/Write Multiple Registers Request instance. - * @param unit Unit ID - */ - public ReadWriteMultipleRequest(int unit) { - super(); - - setUnitID(unit); - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - - // There is no additional data in this request. - setDataLength(9); - } - - /** - * Constructs a new Read/Write Multiple Registers Request instance. - */ - public ReadWriteMultipleRequest() { - super(); - - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - - // There is no additional data in this request. - setDataLength(9); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReadWriteMultipleResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - ReadWriteMultipleResponse response; - InputRegister[] readRegs; - Register[] writeRegs; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - // 2. get input registers range - try { - // First the write - writeRegs = procimg.getRegisterRange(getWriteReference(), getWriteWordCount()); - for (int i = 0; i < writeRegs.length; i++) { - writeRegs[i].setValue(getRegister(i).getValue()); - } - - // And then the read - readRegs = procimg.getRegisterRange(getReadReference(), getReadWordCount()); - InputRegister[] dummy = new InputRegister[readRegs.length]; - for (int i = 0; i < readRegs.length; i++) { - dummy[i] = new SimpleInputRegister(readRegs[i].getValue()); - } - readRegs = dummy; - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (ReadWriteMultipleResponse)getResponse(); - response.setRegisters(readRegs); - - return response; - } - /** - * getReadReference - Returns the reference of the register to start writing - * to with this ReadWriteMultipleRequest. - *

- * - * @return the reference of the register to start writing to as int - * . - */ - public int getReadReference() { - return readReference; - } - - /** - * setReadReference - Sets the reference of the register to writing to with - * this ReadWriteMultipleRequest. - *

- * - * @param ref the reference of the register to start writing to as - * int. - */ - public void setReadReference(int ref) { - readReference = ref; - } - - /** - * getWriteReference - Returns the reference of the register to start - * writing to with this ReadWriteMultipleRequest. - *

- * - * @return the reference of the register to start writing to as int - * . - */ - public int getWriteReference() { - return writeReference; - } - - /** - * setWriteReference - Sets the reference of the register to write to with - * this ReadWriteMultipleRequest. - *

- * - * @param ref the reference of the register to start writing to as - * int. - */ - public void setWriteReference(int ref) { - writeReference = ref; - } - - /** - * getRegisters - Returns the registers to be written with this - * ReadWriteMultipleRequest. - *

- * - * @return the registers to be read as Register[]. - */ - public synchronized Register[] getRegisters() { - Register[] dest = new Register[registers.length]; - System.arraycopy(registers, 0, dest, 0, dest.length); - return dest; - } - - /** - * setRegisters - Sets the registers to be written with this - * ReadWriteMultipleRequest. - *

- * - * @param registers the registers to be written as Register[]. - */ - public void setRegisters(Register[] registers) { - writeCount = registers != null ? registers.length : 0; - this.registers = registers != null ? Arrays.copyOf(registers, registers.length) : null; - } - - /** - * getRegister - Returns the specified Register. - * - * @param index the index of the Register. - * - * @return the register as Register. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public Register getRegister(int index) throws IndexOutOfBoundsException { - if (index < 0) { - throw new IndexOutOfBoundsException(index + " < 0"); - } - - if (index >= getWriteWordCount()) { - throw new IndexOutOfBoundsException(index + " > " + getWriteWordCount()); - } - - return registers[index]; - } - - /** - * getReadRegisterValue - Returns the value of the specified register - * interpreted as unsigned short. - * - * @param index the relative index of the register for which the value should - * be retrieved. - * - * @return the value as int. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public int getReadRegisterValue(int index) throws IndexOutOfBoundsException { - return getRegister(index).toUnsignedShort(); - } - - /** - * getByteCount - Returns the number of bytes representing the values to be - * written. - * - * @return the number of bytes to be written as int. - */ - public int getByteCount() { - return getWriteWordCount() * 2; - } - - /** - * getWriteWordCount - Returns the number of words to be written. - * - * @return the number of words to be written as int. - */ - public int getWriteWordCount() { - return writeCount; - } - - /** - * setWriteWordCount - Sets the number of words to be written. - * - * @param count the number of words to be written as int. - */ - public void setWriteWordCount(int count) { - writeCount = count; - } - - /** - * getReadWordCount - Returns the number of words to be read. - * - * @return the number of words to be read as int. - */ - public int getReadWordCount() { - return readCount; - } - - /** - * setReadWordCount - Sets the number of words to be read. - * - * @param count the number of words to be read as int. - */ - public void setReadWordCount(int count) { - readCount = count; - } - - /** - * getNonWordDataHandler - Returns the actual non word data handler. - * - * @return the actual NonWordDataHandler. - */ - public NonWordDataHandler getNonWordDataHandler() { - return nonWordDataHandler; - } - - /** - * setNonWordDataHandler - Sets a non word data handler. A non-word data - * handler is responsible for converting words from a Modbus packet into the - * non-word values associated with the actual device's registers. - * - * @param dhandler a NonWordDataHandler instance. - */ - public void setNonWordDataHandler(NonWordDataHandler dhandler) { - nonWordDataHandler = dhandler; - } - - /** - * writeData -- output this Modbus message to dout. - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- read the values of the registers to be written, along with - * the reference and count for the registers to be read. - */ - public void readData(DataInput input) throws IOException { - readReference = input.readUnsignedShort(); - readCount = input.readUnsignedShort(); - writeReference = input.readUnsignedShort(); - writeCount = input.readUnsignedShort(); - int byteCount = input.readUnsignedByte(); - - if (nonWordDataHandler == null) { - byte buffer[] = new byte[byteCount]; - input.readFully(buffer, 0, byteCount); - - int offset = 0; - registers = new Register[writeCount]; - - for (int register = 0; register < writeCount; register++) { - registers[register] = new SimpleRegister(buffer[offset], buffer[offset + 1]); - offset += 2; - } - } - else { - nonWordDataHandler.readData(input, writeReference, writeCount); - } - } - - /** - * getMessage -- return a prepared message. - * @return prepared message - */ - public byte[] getMessage() { - byte results[] = new byte[9 + 2 * getWriteWordCount()]; - - results[0] = (byte)(readReference >> 8); - results[1] = (byte)(readReference & 0xFF); - results[2] = (byte)(readCount >> 8); - results[3] = (byte)(readCount & 0xFF); - results[4] = (byte)(writeReference >> 8); - results[5] = (byte)(writeReference & 0xFF); - results[6] = (byte)(writeCount >> 8); - results[7] = (byte)(writeCount & 0xFF); - results[8] = (byte)(writeCount * 2); - - int offset = 9; - for (int i = 0; i < writeCount; i++) { - Register reg = getRegister(i); - byte[] bytes = reg.toBytes(); - - results[offset++] = bytes[0]; - results[offset++] = bytes[1]; - } - return results; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleResponse.java deleted file mode 100644 index e61526a..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReadWriteMultipleResponse.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.InputRegister; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a ReadWriteMultipleResponse. - * - * @author Julie (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReadWriteMultipleResponse extends ModbusResponse { - - private int byteCount; - private InputRegister[] registers; - - /** - * Constructs a new ReadWriteMultipleResponse instance. - * - * @param registers the Register[] holding response registers. - */ - public ReadWriteMultipleResponse(InputRegister[] registers) { - super(); - - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - setDataLength(registers.length * 2 + 1); - - this.registers = Arrays.copyOf(registers, registers.length); - byteCount = registers.length * 2; - } - - /** - * Constructs a new ReadWriteMultipleResponse instance. - * - * @param count the number of Register[] holding response registers. - */ - public ReadWriteMultipleResponse(int count) { - super(); - - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - setDataLength(count * 2 + 1); - - registers = new InputRegister[count]; - byteCount = count * 2; - } - - /** - * Constructs a new ReadWriteMultipleResponse instance. - */ - public ReadWriteMultipleResponse() { - super(); - - setFunctionCode(Modbus.READ_WRITE_MULTIPLE); - } - - /** - * Returns the number of bytes that have been read. - * - * @return the number of bytes that have been read as int. - */ - public int getByteCount() { - return byteCount; - } - - /** - * Returns the number of words that have been read. The returned value - * should be half of the the byte count of this - * ReadWriteMultipleResponse. - * - * @return the number of words that have been read as int. - */ - public int getWordCount() { - return byteCount / 2; - } - - /** - * Returns the Register at the given position (relative to the - * reference used in the request). - * - * @param index the relative index of the InputRegister. - * - * @return the register as InputRegister. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public InputRegister getRegister(int index) { - if (registers == null) { - throw new IndexOutOfBoundsException("No registers defined!"); - } - - if (index < 0) { - throw new IndexOutOfBoundsException("Negative index: " + index); - } - - if (index >= getWordCount()) { - throw new IndexOutOfBoundsException(index + " > " + getWordCount()); - } - - return registers[index]; - } - - /** - * Returns the value of the register at the given position (relative to the - * reference used in the request) interpreted as unsigned short. - * - * @param index the relative index of the register for which the value should - * be retrieved. - * - * @return the value as int. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public int getRegisterValue(int index) throws IndexOutOfBoundsException { - return getRegister(index).toUnsignedShort(); - } - - /** - * Returns the reference to the array of registers read. - * - * @return a InputRegister[] instance. - */ - public synchronized InputRegister[] getRegisters() { - InputRegister[] dest = new InputRegister[registers.length]; - System.arraycopy(registers, 0, dest, 0, dest.length); - return dest; - } - - /** - * Sets the entire block of registers for this response - * @param registers Array of registers - */ - public void setRegisters(InputRegister[] registers) { - byteCount = registers.length * 2; - setDataLength(byteCount + 1); - - this.registers = Arrays.copyOf(registers, registers.length); - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeByte(byteCount); - - for (int k = 0; k < getWordCount(); k++) { - dout.write(registers[k].toBytes()); - } - } - - public void readData(DataInput din) throws IOException { - byteCount = din.readUnsignedByte(); - - registers = new Register[getWordCount()]; - - for (int k = 0; k < getWordCount(); k++) { - registers[k] = new SimpleRegister(din.readByte(), din.readByte()); - } - - setDataLength(byteCount + 1); - } - - public byte[] getMessage() { - byte result[]; - - result = new byte[getWordCount() * 2 + 1]; - - int offset = 0; - result[offset++] = (byte)byteCount; - - for (InputRegister register : registers) { - byte[] data = register.toBytes(); - - result[offset++] = data[0]; - result[offset++] = data[1]; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDRequest.java deleted file mode 100644 index c5d6cd6..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDRequest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Read MEI Data request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author jfhaugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReportSlaveIDRequest extends ModbusRequest { - - /** - * Constructs a new Report Slave ID request - * instance. - */ - public ReportSlaveIDRequest() { - super(); - - setFunctionCode(Modbus.REPORT_SLAVE_ID); - - // There is no additional data in this request. - setDataLength(0); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new ReportSlaveIDResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - return createExceptionResponse(Modbus.ILLEGAL_FUNCTION_EXCEPTION); - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- dummy function. There is no data with the request. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - } - - /** - * getMessage - * @return an empty array as there is no data for this request - */ - public byte[] getMessage() { - - return new byte[0]; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDResponse.java deleted file mode 100644 index eaf41ee..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/ReportSlaveIDResponse.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a ReadMEIResponse. - * - * Derived from similar class for Read Coils response. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ReportSlaveIDResponse extends ModbusResponse { - - // Message fields. - int m_length; - byte m_data[]; - int m_status; - int m_slaveId; - - /** - * Constructs a new ReportSlaveIDResponse - * instance. - */ - public ReportSlaveIDResponse() { - super(); - setFunctionCode(Modbus.REPORT_SLAVE_ID); - } - - /** - * getSlaveID -- return the slave identifier field. - * @return slave identifier field - */ - public int getSlaveID() { - return m_slaveId; - } - - /** - * setSlaveID -- initialize the slave identifier when constructing - * a response message. - * @param unitID UnitID of the slave - */ - public void setSlaveID(int unitID) { - m_slaveId = unitID; - } - - /** - * getStatus -- get the slave's "run" status. - * - * @return boolean - */ - public boolean getStatus() { - return m_status != 0; - } - - /** - * setStatus -- initialize the slave's "run" status when constructing - * a response message. - * - * @param b Status value - */ - public void setStatus(boolean b) { - m_status = b ? 0xff : 0x00; - } - - /** - * getData -- get the device-depending data for the slave. - * - * @return byte array - */ - public byte[] getData() { - byte[] result = new byte[m_length - 2]; - System.arraycopy(m_data, 0, result, 0, m_length - 2); - - return result; - } - - /** - * setData -- initialize the slave's device dependent data when - * initializing a response. - * - * @param data byte array - */ - public void setData(byte[] data) { - // There are always two bytes of payload in the message -- the - // slave ID and the run status indicator. - if (data == null) { - m_length = 2; - m_data = new byte[0]; - - return; - } - - if (data.length > 249) { - throw new IllegalArgumentException("data length limit exceeded"); - } - - m_length = data.length + 2; - - m_data = new byte[data.length]; - System.arraycopy(data, 0, m_data, 0, data.length); - } - - /** - * writeData -- output the completed Modbus message to dout - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- input the Modbus message from din. If there was a - * header, such as for Modbus/TCP, it will have been read - * already. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - - // Get the size of any device-specific data. - m_length = din.readUnsignedByte(); - if (m_length < 2 || m_length > 255) { - return; - } - - // Get the run status and device identifier. - m_slaveId = din.readUnsignedByte(); - m_status = din.readUnsignedByte(); - - /* - * The device-specific data is two bytes shorter than the - * length read previously. That length includes the run status - * and slave ID. - */ - m_data = new byte[m_length - 2]; - if (m_length > 2) { - din.readFully(m_data, 0, m_length - 2); - } - } - - /** - * getMessage -- format the message into a byte array. - * @return Byte array of message - */ - public byte[] getMessage() { - byte result[] = new byte[3 + m_length]; - int offset = 0; - - result[offset++] = (byte)(m_length + 2); - result[offset++] = (byte)m_slaveId; - result[offset++] = (byte)m_status; - if (m_length > 0) { - System.arraycopy(m_data, 0, result, offset, m_length - 2); - } - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilRequest.java deleted file mode 100644 index 67ac0af..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilRequest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.DigitalOut; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteCoilRequest. The implementation directly - * correlates with the class 0 function write coil (FC 5). It - * encapsulates the corresponding request message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteCoilRequest extends ModbusRequest { - - // instance attributes - private int reference; - private boolean coil; - - /** - * Constructs a new WriteCoilRequest instance. - */ - public WriteCoilRequest() { - super(); - - setFunctionCode(Modbus.WRITE_COIL); - setDataLength(4); - } - - /** - * Constructs a new WriteCoilRequest instance with a given - * reference and state to be written. - * - * @param ref the reference number of the register to read from. - * @param b true if the coil should be set of false if it should be unset. - */ - public WriteCoilRequest(int ref, boolean b) { - super(); - - setFunctionCode(Modbus.WRITE_COIL); - setDataLength(4); - - setReference(ref); - setCoil(b); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new WriteCoilResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - WriteCoilResponse response; - DigitalOut dout; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get coil - try { - dout = procimg.getDigitalOut(getReference()); - // 3. set coil - dout.set(getCoil()); - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (WriteCoilResponse)getResponse(); - response.setReference(getReference()); - response.setCoil(getCoil()); - - return response; - } - - /** - * Returns the reference of the register of the coil that should be written - * to with this ReadCoilsRequest. - * - * @return the reference of the coil's register. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register of the coil that should be written to - * with this ReadCoilsRequest. - *

- * - * @param ref the reference of the coil's register. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the state that should be written with this - * WriteCoilRequest. - * - * @return true if the coil should be set of false if it should be unset. - */ - public boolean getCoil() { - return coil; - } - - /** - * Sets the state that should be written with this WriteCoilRequest. - * - * @param b true if the coil should be set of false if it should be unset. - */ - public void setCoil(boolean b) { - coil = b; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - - if (coil) { - dout.write(Modbus.COIL_ON_BYTES, 0, 2); - } - else { - dout.write(Modbus.COIL_OFF_BYTES, 0, 2); - } - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - - if (din.readByte() == Modbus.COIL_ON) { - coil = true; - } - else { - coil = false; - } - - // discard the next byte. - din.readByte(); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - if (coil) { - result[2] = Modbus.COIL_ON_BYTES[0]; - result[3] = Modbus.COIL_ON_BYTES[1]; - } - else { - result[2] = Modbus.COIL_OFF_BYTES[0]; - result[3] = Modbus.COIL_OFF_BYTES[1]; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilResponse.java deleted file mode 100644 index 81702c4..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteCoilResponse.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteCoilResponse. The implementation directly - * correlates with the class 0 function write coil (FC 5). It - * encapsulates the corresponding response message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteCoilResponse extends ModbusResponse { - private boolean coil = false; - private int reference; - - /** - * Constructs a new WriteCoilResponse instance. - */ - public WriteCoilResponse() { - super(); - - setFunctionCode(Modbus.WRITE_COIL); - setDataLength(4); - } - - /** - * Constructs a new WriteCoilResponse instance. - * - * @param reference the offset were writing was started from. - * @param b the state of the coil; true set, false reset. - */ - public WriteCoilResponse(int reference, boolean b) { - super(); - - setFunctionCode(Modbus.WRITE_COIL); - setDataLength(4); - - setReference(reference); - setCoil(b); - } - - /** - * Gets the state that has been returned in this WriteCoilRequest. - * - * @return true if the coil is set, false if unset. - */ - public boolean getCoil() { - return coil; - } - - /** - * Sets the state that has been returned in the raw response. - * - * @param b true if the coil should be set of false if it should be unset. - */ - public void setCoil(boolean b) { - coil = b; - } - - /** - * Returns the reference of the register of the coil that has been written - * to with the request. - *

- * - * @return the reference of the coil's register. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register of the coil that has been written to - * with the request. - *

- * - * @param ref the reference of the coil's register. - */ - public void setReference(int ref) { - reference = ref; - } - - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - public void readData(DataInput din) throws IOException { - byte data[] = new byte[4]; - din.readFully(data); - - setReference(((data[0] << 8) | (data[1] & 0xff))); - setCoil(data[2] == Modbus.COIL_ON); - - setDataLength(4); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - if (coil) { - result[2] = Modbus.COIL_ON_BYTES[0]; - result[3] = Modbus.COIL_ON_BYTES[1]; - } - else { - result[2] = Modbus.COIL_OFF_BYTES[0]; - result[3] = Modbus.COIL_OFF_BYTES[1]; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordRequest.java deleted file mode 100644 index 413a745..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordRequest.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.msg.WriteFileRecordResponse.RecordResponse; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.*; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a Write File Record request. - * - * @author Julie Haugh (jfh@ghgande.com) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteFileRecordRequest extends ModbusRequest { - private RecordRequest[] records; - - /** - * Constructs a new Write File Record request - * instance. - */ - public WriteFileRecordRequest() { - super(); - - setFunctionCode(Modbus.WRITE_FILE_RECORD); - - // Set up space for the initial header. - setDataLength(1); - } - - /** - * getRequestSize -- return the total request size. This is useful - * for determining if a new record can be added. - * - * @return size in bytes of response. - */ - public int getRequestSize() { - if (records == null) { - return 1; - } - - int size = 1; - for (RecordRequest record : records) { - size += record.getRequestSize(); - } - - return size; - } - - /** - * getRequestCount -- return the number of record requests in this - * message. - * @return number of record requests in this message - */ - public int getRequestCount() { - if (records == null) { - return 0; - } - - return records.length; - } - - /** - * getRecord -- return the record request indicated by the reference - * @param reference Register reference - * @return the record request indicated by the reference - */ - public RecordRequest getRecord(int reference) { - return records[reference]; - } - - /** - * addRequest -- add a new record request. - * @param request Request record - */ - public void addRequest(RecordRequest request) { - if (request.getRequestSize() + getRequestSize() > 248) { - throw new IllegalArgumentException(); - } - - if (records == null) { - records = new RecordRequest[1]; - } - else { - RecordRequest old[] = records; - records = new RecordRequest[old.length + 1]; - - System.arraycopy(old, 0, records, 0, old.length); - } - records[records.length - 1] = request; - - setDataLength(getRequestSize()); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new WriteFileRecordResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - WriteFileRecordResponse response = (WriteFileRecordResponse)getResponse(); - - // Get the process image. - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - // There is a list of requests to be resolved. - try { - for (int i = 0; i < getRequestCount(); i++) { - RecordRequest recordRequest = getRecord(i); - if (recordRequest.getFileNumber() < 0 || recordRequest.getFileNumber() >= procimg.getFileCount()) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - File file = procimg.getFileByNumber(recordRequest.getFileNumber()); - - if (recordRequest.getRecordNumber() < 0 || recordRequest.getRecordNumber() >= file.getRecordCount()) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - Record record = file.getRecord(recordRequest.getRecordNumber()); - int registers = recordRequest.getWordCount(); - if (record == null && registers != 0) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - short data[] = new short[registers]; - for (int j = 0; j < registers; j++) { - Register register = record.getRegister(j); - if (register == null) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - - register.setValue(recordRequest.getRegister(j).getValue()); - data[j] = recordRequest.getRegister(j).toShort(); - } - RecordResponse recordResponse = new RecordResponse(file.getFileNumber(), record == null ? 0 : record.getRecordNumber(), data); - response.addResponse(recordResponse); - } - } - catch (IllegalAddressException e) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - return response; - } - - /** - * writeData -- output this Modbus message to dout. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - /** - * readData -- convert the byte stream into a request. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - int byteCount = din.readUnsignedByte(); - - records = new RecordRequest[0]; - - for (int offset = 1; offset + 7 < byteCount; ) { - int function = din.readUnsignedByte(); - int file = din.readUnsignedShort(); - int record = din.readUnsignedShort(); - int count = din.readUnsignedShort(); - - offset += 7; - - if (function != 6) { - throw new IOException(); - } - - if (record < 0 || record >= 10000) { - throw new IOException(); - } - - if (count < 0 || count >= 126) { - throw new IOException(); - } - - short registers[] = new short[count]; - for (int j = 0; j < count; j++) { - registers[j] = din.readShort(); - offset += 2; - } - RecordRequest dummy[] = new RecordRequest[records.length + 1]; - if (records.length > 0) { - System.arraycopy(records, 0, dummy, 0, records.length); - } - - records = dummy; - records[records.length - 1] = new RecordRequest(file, record, registers); - } - } - - /** - * getMessage -- return the raw binary message. - * @return the raw binary message - */ - public byte[] getMessage() { - byte results[] = new byte[getRequestSize()]; - - results[0] = (byte)(getRequestSize() - 1); - - int offset = 1; - for (RecordRequest record : records) { - record.getRequest(results, offset); - offset += record.getRequestSize(); - } - return results; - } - - public static class RecordRequest { - private int fileNumber; - private int recordNumber; - private int wordCount; - private byte data[]; - - public RecordRequest(int file, int record, short[] values) { - fileNumber = file; - recordNumber = record; - wordCount = values.length; - data = new byte[wordCount * 2]; - - int offset = 0; - for (int i = 0; i < wordCount; i++) { - data[offset++] = (byte)(values[i] >> 8); - data[offset++] = (byte)(values[i] & 0xFF); - } - } - - public int getFileNumber() { - return fileNumber; - } - - public int getRecordNumber() { - return recordNumber; - } - - public int getWordCount() { - return wordCount; - } - - public SimpleRegister getRegister(int register) { - if (register < 0 || register >= wordCount) { - throw new IllegalAddressException("0 <= " + register + " < " + wordCount); - } - byte b1 = data[register * 2]; - byte b2 = data[register * 2 + 1]; - - return new SimpleRegister(b1, b2); - } - - /** - * getRequestSize -- return the size of the response in bytes. - * @return the size of the response in bytes - */ - public int getRequestSize() { - return 7 + wordCount * 2; - } - - public void getRequest(byte[] request, int offset) { - request[offset++] = 6; - request[offset++] = (byte)(fileNumber >> 8); - request[offset++] = (byte)(fileNumber & 0xFF); - request[offset++] = (byte)(recordNumber >> 8); - request[offset++] = (byte)(recordNumber & 0xFF); - request[offset++] = (byte)(wordCount >> 8); - request[offset++] = (byte)(wordCount & 0xFF); - - System.arraycopy(data, 0, request, offset, data.length); - } - - public byte[] getRequest() { - byte[] request = new byte[7 + 2 * wordCount]; - - getRequest(request, 0); - - return request; - } - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordResponse.java deleted file mode 100644 index 3b3d5bc..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteFileRecordResponse.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteFileRecordResponse. - * - * @author Julie - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteFileRecordResponse extends ModbusResponse { - private RecordResponse[] records; - - /** - * Constructs a new WriteFileRecordResponse instance. - */ - public WriteFileRecordResponse() { - super(); - - setFunctionCode(Modbus.WRITE_FILE_RECORD); - setDataLength(7); - } - - /** - * getRequestSize -- return the total request size. This is useful - * for determining if a new record can be added. - * - * @return size in bytes of response. - */ - public int getResponseSize() { - if (records == null) { - return 1; - } - - int size = 1; - for (RecordResponse record : records) { - size += record.getResponseSize(); - } - - return size; - } - - /** - * getRequestCount -- return the number of record requests in this - * message. - * @return the number of record requests in this message - */ - public int getRequestCount() { - if (records == null) { - return 0; - } - - return records.length; - } - - /** - * getRecord -- return the record request indicated by the reference - * @param index Record to get - * @return the record request indicated by the reference - */ - public RecordResponse getRecord(int index) { - return records[index]; - } - - /** - * addResponse -- add a new record response. - * @param response Add record response - */ - public void addResponse(RecordResponse response) { - if (response.getResponseSize() + getResponseSize() > 248) { - throw new IllegalArgumentException(); - } - - if (records == null) { - records = new RecordResponse[1]; - } - else { - RecordResponse old[] = records; - records = new RecordResponse[old.length + 1]; - - System.arraycopy(old, 0, records, 0, old.length); - } - records[records.length - 1] = response; - - setDataLength(getResponseSize()); - } - - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - public void readData(DataInput din) throws IOException { - int byteCount = din.readUnsignedByte(); - - records = new RecordResponse[0]; - - for (int offset = 1; offset + 7 < byteCount; ) { - int function = din.readUnsignedByte(); - int file = din.readUnsignedShort(); - int record = din.readUnsignedShort(); - int count = din.readUnsignedShort(); - - offset += 7; - - if (function != 6) { - throw new IOException(); - } - - if (record < 0 || record >= 10000) { - throw new IOException(); - } - - if (count < 0 || count >= 126) { - throw new IOException(); - } - - short registers[] = new short[count]; - for (int j = 0; j < count; j++) { - registers[j] = din.readShort(); - offset += 2; - } - RecordResponse dummy[] = new RecordResponse[records.length + 1]; - if (records.length > 0) { - System.arraycopy(records, 0, dummy, 0, records.length); - } - - records = dummy; - records[records.length - 1] = new RecordResponse(file, record, registers); - } - } - - public byte[] getMessage() { - byte results[] = new byte[getResponseSize()]; - - results[0] = (byte)(getResponseSize() - 1); - - int offset = 1; - for (RecordResponse record : records) { - record.getResponse(results, offset); - offset += record.getResponseSize(); - } - return results; - } - - public static class RecordResponse { - private int fileNumber; - private int recordNumber; - private int wordCount; - private byte data[]; - - public RecordResponse(int file, int record, short[] values) { - fileNumber = file; - recordNumber = record; - wordCount = values.length; - data = new byte[wordCount * 2]; - - int offset = 0; - for (int i = 0; i < wordCount; i++) { - data[offset++] = (byte)(values[i] >> 8); - data[offset++] = (byte)(values[i] & 0xFF); - } - } - - public int getFileNumber() { - return fileNumber; - } - - public int getRecordNumber() { - return recordNumber; - } - - public int getWordCount() { - return wordCount; - } - - public SimpleRegister getRegister(int register) { - if (register < 0 || register >= wordCount) { - throw new IndexOutOfBoundsException("0 <= " + register + " < " + wordCount); - } - byte b1 = data[register * 2]; - byte b2 = data[register * 2 + 1]; - - return new SimpleRegister(b1, b2); - } - - /** - * getResponseSize -- return the size of the response in bytes. - * @return the size of the response in bytes - */ - public int getResponseSize() { - return 7 + wordCount * 2; - } - - public void getResponse(byte[] response, int offset) { - response[offset++] = 6; - response[offset++] = (byte)(fileNumber >> 8); - response[offset++] = (byte)(fileNumber & 0xFF); - response[offset++] = (byte)(recordNumber >> 8); - response[offset++] = (byte)(recordNumber & 0xFF); - response[offset++] = (byte)(wordCount >> 8); - response[offset++] = (byte)(wordCount & 0xFF); - - System.arraycopy(data, 0, response, offset, data.length); - } - - public byte[] getResponse() { - byte[] response = new byte[7 + 2 * wordCount]; - - getResponse(response, 0); - - return response; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsRequest.java deleted file mode 100644 index 4658cf6..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsRequest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.DigitalOut; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.util.BitVector; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteMultipleCoilsRequest. The implementation - * directly correlates with the class 1 function write multiple coils (FC - * 15). It encapsulates the corresponding request message. - * - *

- * Coils are understood as bits that can be manipulated (i.e. set or cleared). - *

- * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteMultipleCoilsRequest extends ModbusRequest { - - // instance attributes - private int reference; - private BitVector coils; - - /** - * Constructs a new WriteMultipleCoilsRequest instance with the - * given reference and coil values. - * - * @param ref the index of the first coil to be written. - * @param bv the coil values to be written. - */ - public WriteMultipleCoilsRequest(int ref, BitVector bv) { - super(); - - setFunctionCode(Modbus.WRITE_MULTIPLE_COILS); - setDataLength(bv.byteSize() + 5); - - setReference(ref); - coils = bv; - } - - /** - * Constructs a new WriteMultipleCoilsRequest instance with a given - * reference and count of coils to be written, followed by the actual byte - * count, and then count number of bytes. - * - * @param ref the index of the first coil to be written. - * @param count the number of coils to be written. - */ - public WriteMultipleCoilsRequest(int ref, int count) { - super(); - - setFunctionCode(Modbus.WRITE_MULTIPLE_COILS); - setDataLength((count + 7) / 8 + 5); - - setReference(ref); - coils = new BitVector(count); - } - - /** - * Constructs a new WriteMultipleCoilsRequest instance. - * - *

- * A minimal message contains the reference to the first coil as a - * short, the number of coils as a short, and not less - * than one byte of coil data. - */ - public WriteMultipleCoilsRequest() { - super(); - - setFunctionCode(Modbus.WRITE_MULTIPLE_COILS); - setDataLength(5); - - coils = new BitVector(1); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new WriteMultipleCoilsResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - WriteMultipleCoilsResponse response; - DigitalOut douts[]; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get coil range - try { - douts = procimg.getDigitalOutRange(reference, coils.size()); - // 3. set coils - for (int i = 0; i < douts.length; i++) { - douts[i].set(coils.getBit(i)); - } - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (WriteMultipleCoilsResponse)getResponse(); - response.setBitCount(coils.size()); - response.setReference(reference); - - return response; - } - - /** - * getReference - Returns the reference of the coil to to start writing to - * with this WriteMultipleCoilsRequest. - * - * @return the reference of the coil to start writing to as an int. - */ - public int getReference() { - return reference; - } - - /** - * setReference - Sets the reference of the coil to start writing to with - * this WriteMultipleCoilsRequest. - * - * @param ref the reference of the coil to start writing to. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * getBitCount - Returns the number of coils written with the request. - * - * @return the number of coils that have been written. - */ - public int getBitCount() { - if (coils == null) { - return 0; - } - else { - return coils.size(); - } - } - - /** - * getByteCount - Returns the number of bytes required for packing the - * coils. - * - * @return the number of bytes required for packing the coils. - */ - public int getByteCount() { - return coils.byteSize(); - } - - /** - * getCoilStatus - Returns the status of the specified coil. - * - * @param index the index of the coil to be tested. - * - * @return true if set, false otherwise. - * - * @throws IndexOutOfBoundsException if the given index is out of bounds. - */ - public boolean getCoilStatus(int index) throws IndexOutOfBoundsException { - return coils.getBit(index); - } - - /** - * setCoilStatus - Sets the status of the specified coil. - * - * @param index the index of the coil to be set/reset. - * @param b true if to be set, false for reset. - * - * @throws IndexOutOfBoundsException if the given index is out of bounds. - */ - public void setCoilStatus(int index, boolean b) throws IndexOutOfBoundsException { - coils.setBit(index, b); - } - - /** - * getCoils - Returns the BitVector instance holding coil status - * information. - * - * @return the coils status as a BitVector instance. - */ - public BitVector getCoils() { - return coils; - } - - /** - * setCoils - Sets the BitVector instance holding coil status - * information. - * - * @param bv a BitVector instance holding coil status info. - */ - public void setCoils(BitVector bv) { - coils = bv; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - dout.writeShort(coils.size()); - - dout.writeByte(coils.byteSize()); - dout.write(coils.getBytes()); - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - int bitcount = din.readUnsignedShort(); - int coilBytes = din.readUnsignedByte(); - byte[] data = new byte[coilBytes]; - - for (int k = 0; k < coilBytes; k++) { - data[k] = din.readByte(); - } - - // decode bytes into BitVector, sets data and bitcount - coils = BitVector.createBitVector(data, bitcount); - - // update data length - setDataLength(coilBytes + 5); - } - - public byte[] getMessage() { - int len = coils.byteSize() + 5; - byte result[] = new byte[len]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - - result[2] = (byte)((coils.size() >> 8) & 0xff); - result[3] = (byte)(coils.size() & 0xff); - - result[4] = (byte)coils.byteSize(); - - System.arraycopy(coils.getBytes(), 0, result, 5, coils.byteSize()); - - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsResponse.java deleted file mode 100644 index 7288618..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleCoilsResponse.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteMultipleCoilsResponse. The implementation - * directly correlates with the class 1 function write multiple coils (FC - * 15). It encapsulates the corresponding response message. - *

- * Coils are understood as bits that can be manipulated (i.e. set or cleared). - * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteMultipleCoilsResponse extends ModbusResponse { - - // instance attributes - private int reference; - private int bitCount; - - /** - * Constructs a new WriteMultipleCoilsResponse instance with a - * given count of coils and starting reference. - *

- * - * @param ref the offset to begin writing from. - * @param count the number of coils to be written. - */ - public WriteMultipleCoilsResponse(int ref, int count) { - super(); - reference = ref; - bitCount = count; - setDataLength(4); - } - - /** - * Constructs a new WriteMultipleCoilsResponse instance. - */ - public WriteMultipleCoilsResponse() { - super(); - setDataLength(4); - } - - /** - * getReference - Returns the reference of the coil to start reading from - * with this WriteMultipleCoilsResponse. - *

- * - * @return the reference of the coil to start reading from as int. - */ - public int getReference() { - return reference; - } - - /** - * setReference - Sets the reference to the coil that is the first coil in - * this response. - * - * @param ref Rgister address of coil - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * getBitCount - Returns the quantity of coils written with the request. - *

- * - * @return the quantity of coils that have been written. - */ - public int getBitCount() { - return bitCount; - } - - /** - * setBitCount - Sets the number of coils that will be in a response. - * - * @param count the number of coils in the response. - */ - public void setBitCount(int count) { - bitCount = count; - } - - /** - * writeData - Copy the attribute values for this message to the output - * buffer. - * @throws IOException If the data cannot be written - */ - public void writeData(DataOutput dout) throws IOException { - - dout.writeShort(reference); - dout.writeShort(bitCount); - } - - /** - * readData - Initialize the attribute values for this message from the - * input buffer. - * @throws IOException If the data cannot be read - */ - public void readData(DataInput din) throws IOException { - - reference = din.readUnsignedShort(); - bitCount = din.readUnsignedShort(); - } - - public byte[] getMessage() { - byte results[] = new byte[4]; - - results[0] = (byte)((reference >> 8) & 0xff); - results[1] = (byte)(reference & 0xff); - results[2] = (byte)((bitCount >> 8) & 0xff); - results[3] = (byte)(bitCount & 0xff); - - return results; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersRequest.java deleted file mode 100644 index 6d7c32e..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersRequest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.NonWordDataHandler; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -/** - * Class implementing a WriteMultipleRegistersRequest. The - * implementation directly correlates with the class 0 function write - * multiple registers (FC 16). It encapsulates the corresponding request - * message. - * - * @author Dieter Wimberger - * @author jfhaugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteMultipleRegistersRequest extends ModbusRequest { - private int reference; - private Register[] registers; - private NonWordDataHandler nonWordDataHandler = null; - - /** - * Constructs a new WriteMultipleRegistersRequest instance with a - * given starting reference and values to be written. - *

- * - * @param first -- the address of the first register to write to. - * @param registers -- the registers to be written. - */ - public WriteMultipleRegistersRequest(int first, Register[] registers) { - setFunctionCode(Modbus.WRITE_MULTIPLE_REGISTERS); - - setReference(first); - setRegisters(registers); - } - - /** - * Constructs a new WriteMultipleRegistersRequest instance. - */ - public WriteMultipleRegistersRequest() { - setFunctionCode(Modbus.WRITE_MULTIPLE_REGISTERS); - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new WriteMultipleRegistersResponse()); - } - - /** - * createResponse - Returns the WriteMultipleRegistersResponse that - * represents the answer to this WriteMultipleRegistersRequest. - * - * The implementation should take care about assembling the reply to this - * WriteMultipleRegistersRequest. - * - * This method is used to create responses from the process image associated - * with the listener. It is commonly used to implement Modbus - * slave instances. - * - * @return the corresponding ModbusResponse. - *

- * - * createResponse() must be able to handle the case where the word - * data that is in the response is actually non-word data. That is, - * where the slave device has data which are not actually - * short values in the range of registers being processed. - */ - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - WriteMultipleRegistersResponse response; - - if (nonWordDataHandler == null) { - Register[] regs; - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - // 2. get registers - try { - regs = procimg.getRegisterRange(getReference(), getWordCount()); - // 3. set Register values - for (int i = 0; i < regs.length; i++) { - regs[i].setValue(this.getRegister(i).getValue()); - } - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - response = (WriteMultipleRegistersResponse)getResponse(); - response.setReference(getReference()); - response.setWordCount(getWordCount()); - } - else { - int result = nonWordDataHandler.commitUpdate(); - if (result > 0) { - return createExceptionResponse(result); - } - - response = (WriteMultipleRegistersResponse)getResponse(); - response.setReference(getReference()); - response.setWordCount(nonWordDataHandler.getWordCount()); - } - - return response; - } - - /** - * setReference - Returns the reference of the register to start writing to - * with this WriteMultipleRegistersRequest. - *

- * - * @return the reference of the register to start writing to as int - * . - */ - public int getReference() { - return reference; - } - - /** - * setReference - Sets the reference of the register to write to with this - * WriteMultipleRegistersRequest. - *

- * - * @param ref the reference of the register to start writing to as an - * int. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * getRegisters - Returns the registers to be written with this - * WriteMultipleRegistersRequest. - *

- * - * @return the registers to be written as Register[]. - */ - public synchronized Register[] getRegisters() { - Register[] dest = new Register[registers.length]; - System.arraycopy(registers, 0, dest, 0, dest.length); - return dest; - } - - /** - * setRegisters - Sets the registers to be written with this - * WriteMultipleRegistersRequest. - *

- * - * @param registers the registers to be written as Register[]. - */ - public void setRegisters(Register[] registers) { - this.registers = registers == null ? null : Arrays.copyOf(registers, registers.length); - } - - /** - * getRegister - Returns the Register at the given position. - * - * @param index the relative index of the Register. - * - * @return the register as Register. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public Register getRegister(int index) throws IndexOutOfBoundsException { - if (index < 0) { - throw new IndexOutOfBoundsException(index + " < 0"); - } - - if (index >= getWordCount()) { - throw new IndexOutOfBoundsException(index + " > " + getWordCount()); - } - - return registers[index]; - } - - /** - * getRegisterValue - Returns the value of the specified register. - *

- * - * @param index the index of the desired register. - * - * @return the value as an int. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public int getRegisterValue(int index) throws IndexOutOfBoundsException { - return getRegister(index).toUnsignedShort(); - } - - /** - * getByteCount - Returns the number of bytes representing the values to be - * written. - *

- * - * @return the number of bytes to be written as int. - */ - public int getByteCount() { - return getWordCount() * 2; - } - - /** - * getWordCount - Returns the number of words to be written. - * - * @return the number of words to be written as int. - */ - public int getWordCount() { - if (registers == null) { - return 0; - } - - return registers.length; - } - - /** - * getNonWordDataHandler - Returns the actual non word data handler. - * - * @return the actual NonWordDataHandler. - */ - public NonWordDataHandler getNonWordDataHandler() { - return nonWordDataHandler; - } - - /** - * setNonWordHandler - Sets a non word data handler. A non-word data handler - * is responsible for converting words from a Modbus packet into the - * non-word values associated with the actual device's registers. - * - * @param dhandler a NonWordDataHandler instance. - */ - public void setNonWordDataHandler(NonWordDataHandler dhandler) { - nonWordDataHandler = dhandler; - } - - public void writeData(DataOutput output) throws IOException { - output.write(getMessage()); - } - - public void readData(DataInput input) throws IOException { - reference = input.readUnsignedShort(); - int registerCount = input.readUnsignedShort(); - int byteCount = input.readUnsignedByte(); - - if (nonWordDataHandler == null) { - byte buffer[] = new byte[byteCount]; - input.readFully(buffer, 0, byteCount); - - int offset = 0; - registers = new Register[registerCount]; - - for (int register = 0; register < registerCount; register++) { - registers[register] = new SimpleRegister(buffer[offset], buffer[offset + 1]); - offset += 2; - } - } - else { - nonWordDataHandler.readData(input, reference, registerCount); - } - } - - public byte[] getMessage() { - int len = 5; - - if (registers != null) { - len += registers.length * 2; - } - - byte result[] = new byte[len]; - int registerCount = registers != null ? registers.length : 0; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((registerCount >> 8) & 0xff); - result[3] = (byte)(registerCount & 0xff); - result[4] = (byte)(registerCount * 2); - - int offset = 5; - - if (nonWordDataHandler == null) { - for (int i = 0; i < registerCount; i++) { - byte bytes[] = registers[i].toBytes(); - result[offset++] = bytes[0]; - result[offset++] = bytes[1]; - } - } - else { - nonWordDataHandler.prepareData(reference, registerCount); - byte bytes[] = nonWordDataHandler.getData(); - if (bytes != null) { - int nonWordBytes = bytes.length; - if (nonWordBytes > registerCount * 2) { - nonWordBytes = registerCount * 2; - } - - System.arraycopy(bytes, 0, result, offset, nonWordBytes); - } - } - return result; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersResponse.java deleted file mode 100644 index 846585f..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteMultipleRegistersResponse.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteMultipleRegistersResponse. The - * implementation directly correlates with the class 0 function read multiple - * registers (FC 16). It encapsulates the corresponding response message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteMultipleRegistersResponse extends ModbusResponse { - // instance attributes - private int wordCount; - private int reference; - - /** - * Constructs a new WriteMultipleRegistersResponse instance. - */ - public WriteMultipleRegistersResponse() { - super(); - - setFunctionCode(Modbus.WRITE_MULTIPLE_REGISTERS); - setDataLength(4); - } - - /** - * Constructs a new WriteMultipleRegistersResponse instance. - * - * @param reference the offset to start reading from. - * @param wordCount the number of words (registers) to be read. - */ - public WriteMultipleRegistersResponse(int reference, int wordCount) { - super(); - - setFunctionCode(Modbus.WRITE_MULTIPLE_REGISTERS); - setDataLength(4); - - this.reference = reference; - this.wordCount = wordCount; - } - - /** - * Returns the reference of the register to start writing to with this - * WriteMultipleRegistersResponse. - *

- * - * @return the reference of the register to start writing to as int - * . - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to start writing to with this - * WriteMultipleRegistersResponse. - *

- * - * @param ref the reference of the register to start writing to as - * int. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the number of bytes that have been written. - * - * @return the number of bytes that have been read as int. - */ - public int getByteCount() { - return wordCount * 2; - } - - /** - * Returns the number of words that have been read. The returned value - * should be half of the byte count of the response. - *

- * - * @return the number of words that have been read as int. - */ - public int getWordCount() { - return wordCount; - } - - /** - * Sets the number of words that have been returned. - * - * @param count the number of words as int. - */ - public void setWordCount(int count) { - wordCount = count; - } - - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - public void readData(DataInput din) throws IOException { - setReference(din.readUnsignedShort()); - setWordCount(din.readUnsignedShort()); - - setDataLength(4); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((wordCount >> 8) & 0xff); - result[3] = (byte)(wordCount & 0xff); - - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterRequest.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterRequest.java deleted file mode 100644 index f8036cf..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterRequest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.procimg.IllegalAddressException; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.procimg.SimpleRegister; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteSingleRegisterRequest. The implementation - * directly correlates with the class 0 function write single register (FC - * 6). It encapsulates the corresponding request message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteSingleRegisterRequest extends ModbusRequest { - - // instance attributes - private int reference; - private Register register; - - /** - * Constructs a new WriteSingleRegisterRequest instance. - */ - public WriteSingleRegisterRequest() { - super(); - - setFunctionCode(Modbus.WRITE_SINGLE_REGISTER); - setDataLength(4); - } - - /** - * Constructs a new WriteSingleRegisterRequest instance with a - * given reference and value to be written. - * - * @param ref the reference number of the register to read from. - * @param reg the register containing the data to be written. - */ - public WriteSingleRegisterRequest(int ref, Register reg) { - super(); - - setFunctionCode(Modbus.WRITE_SINGLE_REGISTER); - setDataLength(4); - - reference = ref; - register = reg; - } - - @Override - public ModbusResponse getResponse() { - return updateResponseWithHeader(new WriteSingleRegisterResponse()); - } - - @Override - public ModbusResponse createResponse(AbstractModbusListener listener) { - Register reg; - - // 1. get process image - ProcessImage procimg = listener.getProcessImage(getUnitID()); - - // 2. get register - try { - reg = procimg.getRegister(reference); - - // 3. set Register - reg.setValue(register.toBytes()); - } - catch (IllegalAddressException iaex) { - return createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - } - return updateResponseWithHeader(new WriteSingleRegisterResponse(this.getReference(), reg.getValue())); - } - - /** - * Returns the reference of the register to be written to with this - * WriteSingleRegisterRequest. - * - * @return the reference of the register to be written to. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register to be written to with this - * WriteSingleRegisterRequest. - * - * @param ref the reference of the register to be written to. - */ - public void setReference(int ref) { - reference = ref; - } - - /** - * Returns the register to be written with this - * WriteSingleRegisterRequest. - * - * @return the value to be written to the register. - */ - public Register getRegister() { - return register; - } - - /** - * Sets the value that should be written to the register with this - * WriteSingleRegisterRequest. - * - * @param reg the register to be written. - */ - public void setRegister(Register reg) { - register = reg; - } - - public void writeData(DataOutput dout) throws IOException { - dout.writeShort(reference); - dout.write(register.toBytes()); - } - - public void readData(DataInput din) throws IOException { - reference = din.readUnsignedShort(); - register = new SimpleRegister(din.readByte(), din.readByte()); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((register.getValue() >> 8) & 0xff); - result[3] = (byte)(register.getValue() & 0xff); - - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterResponse.java b/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterResponse.java deleted file mode 100644 index e5fee12..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/msg/WriteSingleRegisterResponse.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.msg; - -import com.ghgande.j2mod.modbus.Modbus; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Class implementing a WriteSingleRegisterResponse. - * The implementation directly correlates with the class 0 - * function write single register (FC 6). It - * encapsulates the corresponding response message. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class WriteSingleRegisterResponse - extends ModbusResponse { - - //instance attributes - private int reference; - private int registerValue; - - /** - * Constructs a new WriteSingleRegisterResponse - * instance. - */ - public WriteSingleRegisterResponse() { - super(); - setDataLength(4); - setFunctionCode(Modbus.WRITE_SINGLE_REGISTER); - } - - /** - * Constructs a new WriteSingleRegisterResponse - * instance. - * - * @param reference the offset of the register written. - * @param value the value of the register. - */ - public WriteSingleRegisterResponse(int reference, int value) { - super(); - setReference(reference); - setRegisterValue(value); - setDataLength(4); - setFunctionCode(Modbus.WRITE_SINGLE_REGISTER); - } - - /** - * Returns the value that has been returned in - * this WriteSingleRegisterResponse. - *

- * - * @return the value of the register. - */ - public int getRegisterValue() { - return registerValue; - } - - /** - * Sets the value that has been returned in the - * response message. - *

- * - * @param value the returned register value. - */ - private void setRegisterValue(int value) { - registerValue = value; - } - - /** - * Returns the reference of the register - * that has been written to. - *

- * - * @return the reference of the written register. - */ - public int getReference() { - return reference; - } - - /** - * Sets the reference of the register that has - * been written to. - *

- * - * @param ref the reference of the written register. - */ - private void setReference(int ref) { - reference = ref; - //setChanged(true); - } - - public void writeData(DataOutput dout) throws IOException { - dout.write(getMessage()); - } - - public void readData(DataInput din) throws IOException { - setReference(din.readUnsignedShort()); - setRegisterValue(din.readUnsignedShort()); - //update data length - setDataLength(4); - } - - public byte[] getMessage() { - byte result[] = new byte[4]; - - result[0] = (byte)((reference >> 8) & 0xff); - result[1] = (byte)(reference & 0xff); - result[2] = (byte)((registerValue >> 8) & 0xff); - result[3] = (byte)(registerValue & 0xff); - - return result; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractModbusListener.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractModbusListener.java deleted file mode 100644 index 7334ed0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractModbusListener.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.msg.ModbusRequest; -import com.ghgande.j2mod.modbus.msg.ModbusResponse; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.slave.ModbusSlave; -import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; - -/** - * Definition of a listener class - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class AbstractModbusListener implements Runnable { - - private static final Logger logger = LoggerFactory.getLogger(AbstractModbusListener.class); - protected int port = Modbus.DEFAULT_PORT; - protected boolean listening; - protected InetAddress address; - protected String error; - protected int timeout = Modbus.DEFAULT_TIMEOUT; - - /** - * Main execution loop for this Modbus interface listener - this is called by - * starting the main listening thread - */ - public abstract void run(); - - /** - * Stop the listener thread for this ModbusListener instance. - */ - public abstract void stop(); - - /** - * Sets the port to be listened to. - * - * @param port the number of the IP port as int. - */ - public void setPort(int port) { - this.port = ((port > 0) ? port : Modbus.DEFAULT_PORT); - } - - /** - * Returns the port being listened on - * - * @return Port number > 0 - */ - public int getPort() { - return port; - } - - /** - * Sets the address of the interface to be listened to. - * - * @param addr an InetAddress instance. - */ - public void setAddress(InetAddress addr) { - address = addr; - } - - /** - * Returns the address bound to this socket - * - * @return Bound address - */ - public InetAddress getAddress() { - return address; - } - - /** - * Tests if this ModbusTCPListener is listening and accepting - * incoming connections. - * - * @return true if listening (and accepting incoming connections), false - * otherwise. - */ - public boolean isListening() { - return listening; - } - - /** - * Set the listening state of this ModbusTCPListener object. - * A ModbusTCPListener will silently drop any requests if the - * listening state is set to false. - * - * @param b listening state - */ - public void setListening(boolean b) { - listening = b; - } - - /** - * Returns any startup errors that may have aoccurred - * - * @return Error string - */ - public String getError() { - return error; - } - - /** - * Get the socket timeout - * - * @return Socket timeout in milliseconds - */ - public int getTimeout() { - return timeout; - } - - /** - * Sets the socket timeout - * - * @param timeout Timeout in milliseconds - */ - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - /** - * Reads the request, checks it is valid and that the unit ID is ok - * and sends back a response - * - * @param transport Transport to read request from - * @param listener Listener that the request was received by - * @throws ModbusIOException If there is an issue with the transport or transmission - */ - void handleRequest(AbstractModbusTransport transport, AbstractModbusListener listener) throws ModbusIOException { - - // Get the request from the transport. It will be processed - // using an associated process image - - if (transport == null) { - throw new ModbusIOException("No transport specified"); - } - ModbusRequest request = transport.readRequest(listener); - if (request == null) { - throw new ModbusIOException("Request for transport %s is invalid (null)", transport.getClass().getSimpleName()); - } - ModbusResponse response; - - // Test if Process image exists for this Unit ID - ProcessImage spi = getProcessImage(request.getUnitID()); - if (spi == null) { - response = request.createExceptionResponse(Modbus.ILLEGAL_ADDRESS_EXCEPTION); - response.setAuxiliaryType(ModbusResponse.AuxiliaryMessageTypes.UNIT_ID_MISSMATCH); - } - else { - response = request.createResponse(this); - } - if (logger.isDebugEnabled()) { - logger.debug("Request:{}", request.getHexMessage()); - logger.debug("Response:{}", response.getHexMessage()); - } - - // Write the response - transport.writeResponse(response); - } - - /** - * Returns the related process image for this listener and Unit Id - * - * @param unitId Unit ID - * @return Process image associated with this listener and Unit ID - */ - public ProcessImage getProcessImage(int unitId) { - ModbusSlave slave = ModbusSlaveFactory.getSlave(this); - if (slave != null) { - return slave.getProcessImage(unitId); - } - return null; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractSerialConnection.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractSerialConnection.java deleted file mode 100644 index 60346ea..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractSerialConnection.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; - -import java.io.IOException; -import java.util.Set; - -/** - * Interface that represents a public abstract serial port connection - * - * @author Felipe Herranz - * @version 2.0 (March 2016) - */ -public abstract class AbstractSerialConnection { - - /** - * Parity values - */ - public static final int NO_PARITY = 0; - public static final int ODD_PARITY = 1; - public static final int EVEN_PARITY = 2; - public static final int MARK_PARITY = 3; - public static final int SPACE_PARITY = 4; - - /** - * Stop bits values - */ - public static final int ONE_STOP_BIT = 1; - public static final int ONE_POINT_FIVE_STOP_BITS = 2; - public static final int TWO_STOP_BITS = 3; - - /** - * Flow control values - */ - public static final int FLOW_CONTROL_DISABLED = 0; - public static final int FLOW_CONTROL_RTS_ENABLED = 1; - public static final int FLOW_CONTROL_CTS_ENABLED = 16; - public static final int FLOW_CONTROL_DSR_ENABLED = 256; - public static final int FLOW_CONTROL_DTR_ENABLED = 4096; - public static final int FLOW_CONTROL_XONXOFF_IN_ENABLED = 65536; - public static final int FLOW_CONTROL_XONXOFF_OUT_ENABLED = 1048576; - - /** - * Open delay (msec) - */ - public static final int OPEN_DELAY = 0; - - /** - * Timeout - */ - static final public int TIMEOUT_NONBLOCKING = 0x00000000; - static final public int TIMEOUT_READ_SEMI_BLOCKING = 0x00000001; - static final public int TIMEOUT_WRITE_SEMI_BLOCKING = 0x00000010; - static final public int TIMEOUT_READ_BLOCKING = 0x00000100; - static final public int TIMEOUT_WRITE_BLOCKING = 0x00001000; - static final public int TIMEOUT_SCANNER = 0x00010000; - - /** - * Returns the ModbusTransport instance to be used for receiving - * and sending messages. - * - * @throws IOException If the port is not available or cannot be opened - */ - public abstract void open() throws IOException; - - /** - * Returns the ModbusTransport instance to be used for receiving - * and sending messages. - * - * @return a ModbusTransport instance. - */ - public abstract AbstractModbusTransport getModbusTransport(); - - /** - * Read a specified number of bytes from the serial port - * - * @param buffer Buffer to recieve bytes from the port - * @param bytesToRead Number of bytes to read - * @return number of currently bytes read. - */ - public abstract int readBytes(byte[] buffer, long bytesToRead); - - /** - * Write a specified number of bytes to the serial port - * - * @param buffer Bytes to send to the port - * @param bytesToWrite How many bytes to send - * @return number of currently bytes written - */ - public abstract int writeBytes(byte[] buffer, long bytesToWrite); - - /** - * Bytes available to read - * - * @return number of bytes currently available to read - */ - public abstract int bytesAvailable(); - - /** - * Sets the connection parameters to the setting in the parameters object. - * If set fails return the parameters object to original settings and throw - * exception. - */ - public abstract void setConnectionParameters(); - - /** - * Close the port and clean up associated elements. - */ - public abstract void close(); - - /** - * Returns current baud rate - * - * @return Baud rate - */ - public abstract int getBaudRate(); - - /** - * Set new baud rate - * - * @param newBaudRate Baud rate - */ - public abstract void setBaudRate(int newBaudRate); - - /** - * Returns current data bits value - * - * @return Number of data bits - */ - public abstract int getNumDataBits(); - - /** - * Returns current stop bits - * - * @return Number of stop bits - */ - public abstract int getNumStopBits(); - - /** - * Returns current parity - * - * @return Parity type - */ - public abstract int getParity(); - - /** - * Returns a descriptive name of the current port - * - * @return a String instance. - */ - public abstract String getDescriptivePortName(); - - /** - * Set port timeouts - * - * @param newTimeoutMode Timeout mode - * @param newReadTimeout Read timeout - * @param newWriteTimeout Write timeout - */ - public abstract void setComPortTimeouts(int newTimeoutMode, int newReadTimeout, int newWriteTimeout); - - /** - * Reports the open status of the port. - * - * @return true if port is open, false if port is closed. - */ - public abstract boolean isOpen(); - - /** - * Returns the timeout for this UDPMasterConnection. - * - * @return the timeout as int. - */ - public abstract int getTimeout(); - - /** - * Sets the timeout for this UDPMasterConnection. - * - * @param timeout the timeout as int. - */ - public abstract void setTimeout(int timeout); - - /** - * Returns a set of all the available comm port names - * - * @return Set of comm port names - */ - public abstract Set getCommPorts(); - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractUDPTerminal.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractUDPTerminal.java deleted file mode 100644 index 106b7d3..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/AbstractUDPTerminal.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.ModbusUDPTransport; - -import java.net.DatagramSocket; -import java.net.InetAddress; - -/** - * Interface defining a UDPTerminal. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class AbstractUDPTerminal { - - protected InetAddress address; - protected ModbusUDPTransport transport; - protected boolean active; - protected int port = Modbus.DEFAULT_PORT; - protected int timeout = Modbus.DEFAULT_TIMEOUT; - protected DatagramSocket socket; - - /** - * Gets the local adapter address - * - * @return Adapter address - */ - public InetAddress getAddress() { - return address; - } - - /** - * Returns the local port the terminal is listening on - * - * @return Port number - */ - public synchronized int getPort() { - return port; - } - - /** - * Sets the local port the terminal is running on - * - * @param port Local port - */ - protected synchronized void setPort(int port) { - this.port = port; - } - - /** - * Tests if this UDPSlaveTerminal is active. - * - * @return true if active, false otherwise. - */ - public boolean isActive() { - return active; - } - - /** - * Sets the timeout in milliseconds for this UDPSlaveTerminal. - * - * @param timeout the timeout as int. - */ - public synchronized void setTimeout(int timeout) { - this.timeout = timeout; - } - - /** - * Get the transport - * @return Transport - */ - public ModbusUDPTransport getTransport() { - return transport; - } - - /** - * Activate this UDPTerminal. - * - * @throws Exception if there is a network failure. - */ - public abstract void activate() throws Exception; - - /** - * Deactivates this UDPTerminal. - */ - public abstract void deactivate(); - - /** - * Sends the given message. - * - * @param msg the message as byte[]. - * - * @throws Exception if sending the message fails. - */ - public abstract void sendMessage(byte[] msg) throws Exception; - - /** - * Receives and returns a message. - * - * @return the message as a newly allocated byte[]. - * - * @throws Exception if receiving a message fails. - */ - public abstract byte[] receiveMessage() throws Exception; - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusTCPListener.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusTCPListener.java deleted file mode 100644 index 7403d5b..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusTCPListener.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.util.ThreadPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.*; - -/** - * Class that implements a ModbusTCPListener. - *

- * If listening, it accepts incoming requests passing them on to be handled. - * If not listening, silently drops the requests. - * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusTCPListener extends AbstractModbusListener { - - private static final Logger logger = LoggerFactory.getLogger(ModbusTCPListener.class); - - private ServerSocket serverSocket = null; - private ThreadPool threadPool; - private Thread listener; - private boolean useRtuOverTcp; - - /** - * Constructs a ModbusTCPListener instance.
- * - * @param poolsize the size of the ThreadPool used to handle incoming - * requests. - * @param addr the interface to use for listening. - */ - public ModbusTCPListener(int poolsize, InetAddress addr) { - this(poolsize, addr, false); - } - - /** - * Constructs a ModbusTCPListener instance.
- * - * @param poolsize the size of the ThreadPool used to handle incoming - * requests. - * @param addr the interface to use for listening. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public ModbusTCPListener(int poolsize, InetAddress addr, boolean useRtuOverTcp) { - threadPool = new ThreadPool(poolsize); - address = addr; - this.useRtuOverTcp = useRtuOverTcp; - } - - /** - * /** - * Constructs a ModbusTCPListener instance. This interface is created - * to listen on the wildcard address (0.0.0.0), which will accept TCP packets - * on all available adapters/interfaces - * - * @param poolsize the size of the ThreadPool used to handle incoming - * requests. - */ - public ModbusTCPListener(int poolsize) { - this(poolsize, false); - } - - /** - * /** - * Constructs a ModbusTCPListener instance. This interface is created - * to listen on the wildcard address (0.0.0.0), which will accept TCP packets - * on all available adapters/interfaces - * - * @param poolsize the size of the ThreadPool used to handle incoming - * requests. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public ModbusTCPListener(int poolsize, boolean useRtuOverTcp) { - threadPool = new ThreadPool(poolsize); - try { - address = InetAddress.getByAddress(new byte[]{0, 0, 0, 0}); - } - catch (UnknownHostException ex) { - // Can't happen -- size is fixed. - } - this.useRtuOverTcp = useRtuOverTcp; - } - - @Override - public void setTimeout(int timeout) { - super.setTimeout(timeout); - if (serverSocket != null && listening) { - try { - serverSocket.setSoTimeout(timeout); - } - catch (SocketException e) { - logger.error("Cannot set socket timeout", e); - } - } - } - - @Override - public void run() { - try { - /* - * A server socket is opened with a connectivity queue of a size - * specified in int floodProtection. Concurrent login handling under - * normal circumstances should be alright, denial of service - * attacks via massive parallel program logins can probably be - * prevented. - */ - int floodProtection = 100; - serverSocket = new ServerSocket(port, floodProtection, address); - serverSocket.setSoTimeout(timeout); - logger.debug("Listening to {} (Port {})", serverSocket.toString(), port); - } - - // Catch any fatal errors and set the listening flag to false to indicate an error - catch (Exception e) { - error = String.format("Cannot start TCP listener - %s", e.getMessage()); - listening = false; - return; - } - - listener = Thread.currentThread(); - listening = true; - try { - - // Infinite loop, taking care of resources in case of a lot of - // parallel logins - while (listening) { - Socket incoming; - try { - incoming = serverSocket.accept(); - } - catch (SocketTimeoutException e) { - continue; - } - logger.debug("Making new connection {}", incoming.toString()); - if (listening) { - TCPSlaveConnection slave = new TCPSlaveConnection(incoming, useRtuOverTcp); - slave.setTimeout(timeout); - threadPool.execute(new TCPConnectionHandler(this, slave)); - } - else { - incoming.close(); - } - } - } - catch (IOException e) { - error = String.format("Problem starting listener - %s", e.getMessage()); - } - } - - @Override - public void stop() { - listening = false; - try { - if (serverSocket != null) { - serverSocket.close(); - } - if (listener != null) { - listener.join(); - } - if (threadPool != null) { - threadPool.close(); - } - } - catch (Exception ex) { - logger.error("Error while stopping ModbusTCPListener", ex); - } - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusUDPListener.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusUDPListener.java deleted file mode 100644 index 9dbca0a..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/ModbusUDPListener.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.io.ModbusUDPTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Class that implements a ModbusUDPListener.
- * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusUDPListener extends AbstractModbusListener { - - private static final Logger logger = LoggerFactory.getLogger(ModbusUDPListener.class); - private UDPSlaveTerminal terminal; - - /** - * Create a new ModbusUDPListener instance listening to the given - * interface address. - * - * @param ifc an InetAddress instance. - */ - public ModbusUDPListener(InetAddress ifc) { - address = ifc; - listening = true; - } - - /** - * Constructs a new ModbusUDPListener instance. The address will be set to a - * default value of the wildcard local address and the default Modbus port. - */ - public ModbusUDPListener() { - try { - address = InetAddress.getByAddress(new byte[]{0, 0, 0, 0}); - } - catch (UnknownHostException e) { - // Can't happen -- length is fixed by code. - } - } - - @Override - public void setTimeout(int timeout) { - super.setTimeout(timeout); - if (terminal != null && listening) { - terminal.setTimeout(timeout); - } - } - - /** - * Starts this ModbusUDPListener. - */ - @Override - public void run() { - ModbusUDPTransport transport; - try { - if (address == null) { - terminal = new UDPSlaveTerminal(InetAddress.getByAddress(new byte[]{0, 0, 0, 0})); - } - else { - terminal = new UDPSlaveTerminal(address); - } - terminal.setTimeout(timeout); - terminal.setPort(port); - terminal.activate(); - transport = new ModbusUDPTransport(terminal); - } - - // Catch any fatal errors and set the listening flag to false to indicate an error - catch (Exception e) { - error = String.format("Cannot start UDP listener - %s", e.getMessage()); - listening = false; - return; - } - - listening = true; - try { - while (listening) { - handleRequest(transport, this); - } - } - catch (ModbusIOException ex1) { - if (!ex1.isEOF()) { - logger.error("Exception occurred before EOF while handling request", ex1); - } - } - finally { - try { - terminal.deactivate(); - transport.close(); - } - catch (Exception ex) { - // ignore - } - } - } - - @Override - public void stop() { - terminal.deactivate(); - listening = false; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPConnectionHandler.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPConnectionHandler.java deleted file mode 100644 index 805bc20..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPConnectionHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.ModbusIOException; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class implementing a handler for incoming Modbus/TCP requests. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class TCPConnectionHandler implements Runnable { - - private static final Logger logger = LoggerFactory.getLogger(TCPConnectionHandler.class); - - private TCPSlaveConnection connection; - private AbstractModbusTransport transport; - private AbstractModbusListener listener; - - /** - * Constructs a new TCPConnectionHandler instance. - * - *

- * The connections will be handling using the ModbusCouple class - * and a ProcessImage which provides the interface between the - * slave implementation and the TCPSlaveConnection. - * - * @param listener the listener that handled the incoming request - * @param connection an incoming connection. - */ - public TCPConnectionHandler(AbstractModbusListener listener, TCPSlaveConnection connection) { - this.listener = listener; - this.connection = connection; - transport = this.connection.getModbusTransport(); - } - - @Override - public void run() { - try { - do { - listener.handleRequest(transport, listener); - } while (!Thread.currentThread().isInterrupted()); - } - catch (ModbusIOException ex) { - if (!ex.isEOF()) { - logger.debug(ex.getMessage()); - } - } - finally { - connection.close(); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java deleted file mode 100644 index 07a8885..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.io.ModbusRTUTCPTransport; -import com.ghgande.j2mod.modbus.io.ModbusTCPTransport; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; - -/** - * Class that implements a TCPMasterConnection. - * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class TCPMasterConnection { - - private static final Logger logger = LoggerFactory.getLogger(TCPMasterConnection.class); - - // instance attributes - private Socket socket; - private int timeout = Modbus.DEFAULT_TIMEOUT; - private boolean connected; - - private InetAddress address; - private int port = Modbus.DEFAULT_PORT; - - private ModbusTCPTransport transport; - - private boolean useRtuOverTcp = false; - - /** - * useUrgentData - sent a byte of urgent data when testing the TCP - * connection. - */ - private boolean useUrgentData = false; - - /** - * Constructs a TCPMasterConnection instance with a given - * destination address. - * - * @param adr the destination InetAddress. - */ - public TCPMasterConnection(InetAddress adr) { - address = adr; - } - - /** - * Prepares the associated ModbusTransport of this - * TCPMasterConnection for use. - * - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * - * @throws IOException if an I/O related error occurs. - */ - private void prepareTransport(boolean useRtuOverTcp) throws IOException { - - // If we don't have a transport, or the transport type has changed - if (transport == null || (this.useRtuOverTcp != useRtuOverTcp)) { - - // Save the flag to tell us which transport type to use - this.useRtuOverTcp = useRtuOverTcp; - - // Select the correct transport - if (useRtuOverTcp) { - logger.trace("prepareTransport() -> using RTU over TCP transport."); - transport = new ModbusRTUTCPTransport(socket); - transport.setMaster(this); - } - else { - logger.trace("prepareTransport() -> using standard TCP transport."); - transport = new ModbusTCPTransport(socket); - transport.setMaster(this); - } - } - else { - logger.trace("prepareTransport() -> using custom transport: {}", transport.getClass().getSimpleName()); - transport.setSocket(socket); - } - transport.setTimeout(timeout); - } - - /** - * Opens this TCPMasterConnection. - * - * @throws Exception if there is a network failure. - */ - public synchronized void connect() throws Exception { - connect(useRtuOverTcp); - } - - /** - * Opens this TCPMasterConnection. - * - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * - * @throws Exception if there is a network failure. - */ - public synchronized void connect(boolean useRtuOverTcp) throws Exception { - if (!isConnected()) { - logger.debug("connect()"); - - // Create a socket without auto-connecting - - socket = new Socket(); - socket.setReuseAddress(true); - socket.setSoLinger(true, 1); - socket.setKeepAlive(true); - setTimeout(timeout); - - // Connect - only wait for the timeout number of milliseconds - - socket.connect(new InetSocketAddress(address, port), timeout); - - // Prepare the transport - - prepareTransport(useRtuOverTcp); - connected = true; - } - } - - /** - * Tests if this TCPMasterConnection is connected. - * - * @return true if connected, false otherwise. - */ - public synchronized boolean isConnected() { - if (connected && socket != null) { - if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) { - try { - socket.close(); - } - catch (IOException e) { - logger.error("Socket exception", e); - } - finally { - connected = false; - } - } - else { - /* - * When useUrgentData is set, a byte of urgent data - * will be sent to the server to test the connection. If - * the connection is actually broken, an IException will - * occur and the connection will be closed. - * - * Note: RFC 6093 has decreed that we stop using urgent - * data. - */ - if (useUrgentData) { - try { - socket.sendUrgentData(0); - ModbusUtil.sleep(5); - } - catch (IOException e) { - connected = false; - try { - socket.close(); - } - catch (IOException e1) { - // Do nothing. - } - } - } - } - } - return connected; - } - - /** - * Closes this TCPMasterConnection. - */ - public void close() { - if (connected) { - try { - transport.close(); - } - catch (IOException ex) { - logger.debug("close()", ex); - } - finally { - connected = false; - } - } - } - - /** - * Returns the ModbusTransport associated with this - * TCPMasterConnection. - * - * @return the connection's ModbusTransport. - */ - public AbstractModbusTransport getModbusTransport() { - return transport; - } - - /** - * Set the ModbusTransport associated with this - * TCPMasterConnection - * @param trans associated transport - */ - public void setModbusTransport(ModbusTCPTransport trans) { - transport = trans; - } - - /** - * Returns the timeout (msec) for this TCPMasterConnection. - * - * @return the timeout as int. - */ - public synchronized int getTimeout() { - return timeout; - } - - /** - * Sets the timeout (msec) for this TCPMasterConnection. This is both the - * connection timeout and the transaction timeout - * - * @param timeout - the timeout in milliseconds as an int. - */ - public synchronized void setTimeout(int timeout) { - try { - this.timeout = timeout; - if (socket != null) { - socket.setSoTimeout(timeout); - } - } - catch (IOException ex) { - logger.warn("Could not set timeout to value " + timeout, ex); - } - } - - /** - * Returns the destination port of this TCPMasterConnection. - * - * @return the port number as int. - */ - public int getPort() { - return port; - } - - /** - * Sets the destination port of this TCPMasterConnection. The - * default is defined as Modbus.DEFAULT_PORT. - * - * @param port the port number as int. - */ - public void setPort(int port) { - this.port = port; - } - - /** - * Returns the destination InetAddress of this - * TCPMasterConnection. - * - * @return the destination address as InetAddress. - */ - public InetAddress getAddress() { - return address; - } - - /** - * Sets the destination InetAddress of this - * TCPMasterConnection. - * - * @param adr the destination address as InetAddress. - */ - public void setAddress(InetAddress adr) { - address = adr; - } - - /** - * Gets the current setting of the flag which controls sending - * urgent data to test a network connection. - * - * @return Status - */ - public boolean getUseUrgentData() { - return useUrgentData; - } - - /** - * Set the flag which controls sending urgent data to test a - * network connection. - * - * @param useUrgentData - Connections are testing using urgent data. - */ - public void setUseUrgentData(boolean useUrgentData) { - this.useUrgentData = useUrgentData; - } - - /** - * Returns true if this connection is an RTU over TCP type - * - * @return True if RTU over TCP - */ - public boolean isUseRtuOverTcp() { - return useRtuOverTcp; - } - - /** - * Sets the transport type to use - * Normally set during the connection but can also be set after a connection has been established - * - * @param useRtuOverTcp True if the transport should be interpreted as RTU over tCP - * - * @throws Exception If the connection is not valid - */ - public void setUseRtuOverTcp(boolean useRtuOverTcp) throws Exception { - this.useRtuOverTcp = useRtuOverTcp; - if (isConnected()) { - prepareTransport(useRtuOverTcp); - } - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPSlaveConnection.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPSlaveConnection.java deleted file mode 100644 index 654d9be..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/TCPSlaveConnection.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import com.ghgande.j2mod.modbus.io.ModbusRTUTCPTransport; -import com.ghgande.j2mod.modbus.io.ModbusTCPTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; - -/** - * Class that implements a TCPSlaveConnection. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class TCPSlaveConnection { - - private static final Logger logger = LoggerFactory.getLogger(TCPSlaveConnection.class); - - // instance attributes - private Socket socket; - private int timeout = Modbus.DEFAULT_TIMEOUT; - private boolean connected; - private ModbusTCPTransport transport; - - /** - * Constructs a TCPSlaveConnection instance using a given socket - * instance. - * - * @param socket the socket instance to be used for communication. - */ - public TCPSlaveConnection(Socket socket) { - this(socket, false); - } - - /** - * Constructs a TCPSlaveConnection instance using a given socket - * instance. - * - * @param socket the socket instance to be used for communication. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - */ - public TCPSlaveConnection(Socket socket, boolean useRtuOverTcp) { - try { - setSocket(socket, useRtuOverTcp); - } - catch (IOException ex) { - logger.debug("TCPSlaveConnection::Socket invalid"); - - throw new IllegalStateException("Socket invalid", ex); - } - } - - /** - * Closes this TCPSlaveConnection. - */ - public void close() { - if (connected) { - try { - transport.close(); - socket.close(); - } - catch (IOException ex) { - logger.warn("Could not close socket", ex); - } - connected = false; - } - } - - /** - * Returns the ModbusTransport associated with this - * TCPMasterConnection. - * - * @return the connection's ModbusTransport. - */ - public AbstractModbusTransport getModbusTransport() { - return transport; - } - - /** - * Prepares the associated ModbusTransport of this - * TCPMasterConnection for use. - * - * @param socket the socket to be used for communication. - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws IOException if an I/O related error occurs. - */ - private void setSocket(Socket socket, boolean useRtuOverTcp) throws IOException { - this.socket = socket; - - if (transport == null) { - if (useRtuOverTcp) { - logger.trace("setSocket() -> using RTU over TCP transport."); - transport = new ModbusRTUTCPTransport(socket); - } - else { - logger.trace("setSocket() -> using standard TCP transport."); - transport = new ModbusTCPTransport(socket); - } - } - else { - transport.setSocket(socket); - } - - connected = true; - } - - /** - * Returns the timeout for this TCPSlaveConnection. - * - * @return the timeout as int. - */ - public int getTimeout() { - return timeout; - } - - /** - * Sets the timeout for this TCPSlaveConnection. - * - * @param timeout the timeout in milliseconds as int. - */ - public void setTimeout(int timeout) { - this.timeout = timeout; - - try { - socket.setSoTimeout(timeout); - } - catch (IOException ex) { - logger.warn("Could not set timeout to " + timeout, ex); - } - } - - /** - * Returns the destination port of this TCPSlaveConnection. - * - * @return the port number as int. - */ - public int getPort() { - return socket.getLocalPort(); - } - - /** - * Returns the destination InetAddress of this - * TCPSlaveConnection. - * - * @return the destination address as InetAddress. - */ - public InetAddress getAddress() { - return socket.getLocalAddress(); - } - - /** - * Tests if this TCPSlaveConnection is connected. - * - * @return true if connected, false otherwise. - */ - public boolean isConnected() { - return connected; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterConnection.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterConnection.java deleted file mode 100644 index 04357db..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterConnection.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.AbstractModbusTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; - -/** - * Class that implements a UDPMasterConnection. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class UDPMasterConnection { - - private static final Logger logger = LoggerFactory.getLogger(UDPMasterConnection.class); - - //instance attributes - private UDPMasterTerminal terminal; - private int timeout = Modbus.DEFAULT_TIMEOUT; - private boolean connected; - - private InetAddress address; - private int port = Modbus.DEFAULT_PORT; - - /** - * Constructs a UDPMasterConnection instance - * with a given destination address. - * - * @param adr the destination InetAddress. - */ - public UDPMasterConnection(InetAddress adr) { - address = adr; - } - - /** - * Opens this UDPMasterConnection. - * - * @throws Exception if there is a network failure. - */ - public synchronized void connect() throws Exception { - if (!connected) { - terminal = new UDPMasterTerminal(address); - terminal.setPort(port); - terminal.setTimeout(timeout); - terminal.activate(); - connected = true; - } - } - - /** - * Closes this UDPMasterConnection. - */ - public void close() { - if (connected) { - try { - terminal.deactivate(); - } - catch (Exception ex) { - logger.debug("Exception occurred while closing UDPMasterConnection", ex); - } - connected = false; - } - } - - /** - * Returns the ModbusTransport associated with this - * UDPMasterConnection. - * - * @return the connection's ModbusTransport. - */ - public AbstractModbusTransport getModbusTransport() { - return terminal == null ? null : terminal.getTransport(); - } - - /** - * Returns the terminal used for handling the package traffic. - * - * @return a UDPTerminal instance. - */ - public AbstractUDPTerminal getTerminal() { - return terminal; - } - - /** - * Returns the timeout for this UDPMasterConnection. - * - * @return the timeout as int. - */ - public synchronized int getTimeout() { - return timeout; - } - - /** - * Sets the timeout for this UDPMasterConnection. - * - * @param timeout the timeout as int. - */ - public synchronized void setTimeout(int timeout) { - this.timeout = timeout; - if (terminal != null) { - terminal.setTimeout(timeout); - } - } - - /** - * Returns the destination port of this - * UDPMasterConnection. - * - * @return the port number as int. - */ - public int getPort() { - return port; - } - - /** - * Sets the destination port of this - * UDPMasterConnection. - * The default is defined as Modbus.DEFAULT_PORT. - * - * @param port the port number as int. - */ - public void setPort(int port) { - this.port = port; - } - - /** - * Returns the destination InetAddress of this - * UDPMasterConnection. - * - * @return the destination address as InetAddress. - */ - public InetAddress getAddress() { - return address; - } - - /** - * Sets the destination InetAddress of this - * UDPMasterConnection. - * - * @param adr the destination address as InetAddress. - */ - public void setAddress(InetAddress adr) { - address = adr; - } - - /** - * Tests if this UDPMasterConnection is connected. - * - * @return true if connected, false otherwise. - */ - public boolean isConnected() { - return connected; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterTerminal.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterTerminal.java deleted file mode 100644 index c765972..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPMasterTerminal.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.io.ModbusUDPTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; - -/** - * Class implementing a UDPMasterTerminal. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -class UDPMasterTerminal extends AbstractUDPTerminal { - - private static final Logger logger = LoggerFactory.getLogger(UDPMasterTerminal.class); - - /** - * Create a UDP master connection to the specified Internet address. - * - * @param addr Remote address to connect to - */ - UDPMasterTerminal(InetAddress addr) { - address = addr; - } - - /** - * Create an uninitialized UDP master connection. - */ - public UDPMasterTerminal() { - } - - @Override - public synchronized void activate() throws Exception { - if (!isActive()) { - if (socket == null) { - socket = new DatagramSocket(); - } - logger.debug("UDPMasterTerminal::haveSocket():{}", socket.toString()); - logger.debug("UDPMasterTerminal::raddr=:{}:rport:{}", address.toString(), port); - - socket.setReceiveBufferSize(1024); - socket.setSendBufferSize(1024); - socket.setSoTimeout(timeout); - - transport = new ModbusUDPTransport(this); - active = true; - } - logger.debug("UDPMasterTerminal::activated"); - } - - @Override - public synchronized void deactivate() { - try { - logger.debug("UDPMasterTerminal::deactivate()"); - if (socket != null) { - socket.close(); - } - transport = null; - active = false; - } - catch (Exception ex) { - logger.error("Error closing socket", ex); - } - } - - @Override - public synchronized void sendMessage(byte[] msg) throws Exception { - DatagramPacket req = new DatagramPacket(msg, msg.length, address, port); - socket.send(req); - } - - @Override - public synchronized byte[] receiveMessage() throws Exception { - - // The longest possible DatagramPacket is 256 bytes (Modbus message - // limit) plus the 6 byte header. - byte[] buffer = new byte[262]; - DatagramPacket packet = new DatagramPacket(buffer, buffer.length); - socket.setSoTimeout(timeout); - socket.receive(packet); - return buffer; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPSlaveTerminal.java b/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPSlaveTerminal.java deleted file mode 100644 index 15ff4b0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/net/UDPSlaveTerminal.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.net; - -import com.ghgande.j2mod.modbus.io.ModbusUDPTransport; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.util.Hashtable; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Class implementing a UDPSlaveTerminal. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -class UDPSlaveTerminal extends AbstractUDPTerminal { - - private static final Logger logger = LoggerFactory.getLogger(UDPSlaveTerminal.class); - protected Hashtable requests = new Hashtable(342); - private LinkedBlockingQueue sendQueue = new LinkedBlockingQueue(); - private LinkedBlockingQueue receiveQueue = new LinkedBlockingQueue(); - private PacketSender packetSender; - private PacketReceiver packetReceiver; - - /** - * Creates a slave terminal on the specified adapter address - * Use 0.0.0.0 to listen on all adapters - * - * @param localaddress Local address to bind to - */ - protected UDPSlaveTerminal(InetAddress localaddress) { - address = localaddress; - } - - @Override - public synchronized void activate() throws Exception { - if (!isActive()) { - logger.debug("UDPSlaveTerminal.activate()"); - if (address != null && port != -1) { - socket = new DatagramSocket(port, address); - } - else { - socket = new DatagramSocket(); - port = socket.getLocalPort(); - address = socket.getLocalAddress(); - } - logger.debug("UDPSlaveTerminal::haveSocket():{}", socket.toString()); - logger.debug("UDPSlaveTerminal::addr=:{}:port={}", address.toString(), port); - - socket.setReceiveBufferSize(1024); - socket.setSendBufferSize(1024); - - // Never timeout the receive - socket.setSoTimeout(0); - - // Start a sender - packetSender = new PacketSender(socket); - new Thread(packetSender).start(); - logger.debug("UDPSlaveTerminal::sender started()"); - - // Start a receiver - - packetReceiver = new PacketReceiver(socket); - new Thread(packetReceiver).start(); - logger.debug("UDPSlaveTerminal::receiver started()"); - - // Create a transport to use - - transport = new ModbusUDPTransport(this); - logger.debug("UDPSlaveTerminal::transport created"); - active = true; - } - logger.debug("UDPSlaveTerminal::activated"); - } - - @Override - public synchronized void deactivate() { - try { - if (active) { - // Stop receiver - this will stop and close the socket - packetReceiver.stop(); - - // Stop sender gracefully - packetSender.stop(); - - transport = null; - active = false; - } - } - catch (Exception ex) { - logger.error("Error deactivating UDPSlaveTerminal", ex); - } - } - - @Override - public void sendMessage(byte[] msg) throws Exception { - sendQueue.add(msg); - } - - @Override - public byte[] receiveMessage() throws Exception { - return receiveQueue.take(); - } - - /** - * The background thread that is responsible for sending messages in response to requests - */ - class PacketSender implements Runnable { - - private boolean running; - private boolean closed; - private Thread thread; - private DatagramSocket socket; - - /** - * Constructs a sender with th socket - * - * @param socket Socket to use - */ - public PacketSender(DatagramSocket socket) { - running = true; - this.socket = socket; - } - - /** - * Stops the sender - */ - public void stop() { - running = false; - thread.interrupt(); - while (!closed) { - ModbusUtil.sleep(100); - } - } - - /** - * Thread loop that sends messages - */ - public void run() { - closed = false; - thread = Thread.currentThread(); - do { - try { - // Pickup the message and corresponding request - byte[] message = sendQueue.take(); - DatagramPacket req = requests.remove(ModbusUtil.registersToInt(message)); - - // Create new Package with corresponding address and port - if (req != null) { - DatagramPacket res = new DatagramPacket(message, message.length, req.getAddress(), req.getPort()); - socket.send(res); - logger.debug("Sent package from queue"); - } - } - catch (Exception ex) { - // Ignore the error if we are no longer listening - - if (running) { - logger.error("Problem reading UDP socket", ex); - } - } - } while (running); - closed = true; - } - - } - - /** - * The background thread that receives messages and adds them to the process list - * for further analysis - */ - class PacketReceiver implements Runnable { - - private boolean running; - private boolean closed; - private DatagramSocket socket; - - /** - * A receiver thread for reception of UDP messages - * - * @param socket Socket to use - */ - public PacketReceiver(DatagramSocket socket) { - running = true; - this.socket = socket; - } - - /** - * Stops the thread - */ - public void stop() { - running = false; - socket.close(); - while (!closed) { - ModbusUtil.sleep(100); - } - } - - /** - * Background thread for reading UDP messages - */ - public void run() { - closed = false; - do { - try { - // 1. Prepare buffer and receive package - byte[] buffer = new byte[256];// max size - DatagramPacket packet = new DatagramPacket(buffer, buffer.length); - socket.receive(packet); - - // 2. Extract TID and remember request - Integer tid = ModbusUtil.registersToInt(buffer); - requests.put(tid, packet); - - // 3. place the data buffer in the queue - receiveQueue.put(buffer); - logger.debug("Received package to queue"); - } - catch (Exception ex) { - // Ignore the error if we are no longer listening - - if (running) { - logger.error("Problem reading UDP socket", ex); - } - } - } while (running); - closed = true; - } - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/AbstractRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/AbstractRegister.java deleted file mode 100644 index 8eda8c9..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/AbstractRegister.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Abstract class for a register. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class AbstractRegister implements Register { - - /** - * The word (byte[2]) holding the register content. - */ - protected byte[] register = new byte[2]; - - public int getValue() { - return ((register[0] & 0xff) << 8 | (register[1] & 0xff)); - } - - public final int toUnsignedShort() { - return ((register[0] & 0xff) << 8 | (register[1] & 0xff)); - } - - public final short toShort() { - return (short)((register[0] << 8) | (register[1] & 0xff)); - } - - public synchronized byte[] toBytes() { - byte[] dest = new byte[register.length]; - System.arraycopy(register, 0, dest, 0, dest.length); - return dest; - } - - public final void setValue(short s) { - register[0] = (byte)(0xff & (s >> 8)); - register[1] = (byte)(0xff & s); - } - - public final void setValue(byte[] bytes) { - if (bytes.length < 2) { - throw new IllegalArgumentException(); - } - else { - register[0] = bytes[0]; - register[1] = bytes[1]; - } - } - - public final void setValue(int v) { - register[0] = (byte)(0xff & (v >> 8)); - register[1] = (byte)(0xff & v); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DefaultProcessImageFactory.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DefaultProcessImageFactory.java deleted file mode 100644 index aef428c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DefaultProcessImageFactory.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * The default ProcessImageFactory. It creates a new SimpleProcessImage - * each time createProcessImageImplementation() is invoked. - * - * @author Dieter Wimberger - * @author jfhaugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class DefaultProcessImageFactory implements ProcessImageFactory { - - /** - * Returns a new SimpleProcessImage instance. - * - * @return a SimpleProcessImage instance. - */ - public ProcessImageImplementation createProcessImageImplementation() { - return new SimpleProcessImage(); - } - - /** - * Returns a new SimpleDigitalIn instance. - * - * @return a SimpleDigitalIn instance. - */ - public DigitalIn createDigitalIn() { - return new SimpleDigitalIn(); - } - - /** - * Returns a new DigitalIn instance with the given state. - * - * @param state true if set, false otherwise. - * - * @return a SimpleDigitalIn instance. - */ - public DigitalIn createDigitalIn(boolean state) { - return new SimpleDigitalIn(state); - } - - /** - * Returns a new SimpleDigitalOut instance. - * - * @return a SimpleDigitalOut instance. - */ - public DigitalOut createDigitalOut() { - return new SimpleDigitalOut(); - } - - /** - * Returns a new DigitalOut instance with the given state. - * - * @param b true if set, false otherwise. - * - * @return a SimpleDigitalOut instance. - */ - public DigitalOut createDigitalOut(boolean b) { - return new SimpleDigitalOut(b); - } - - /** - * Returns a new SimpleInputRegister instance. - * - * @return a SimpleInputRegister instance. - */ - public InputRegister createInputRegister() { - return new SimpleInputRegister(); - } - - /** - * Returns a new InputRegister instance with a given value. - * - * @param b1 the first byte. - * @param b2 the second byte. - * - * @return an InputRegister instance. - */ - public InputRegister createInputRegister(byte b1, byte b2) { - return new SimpleInputRegister(b1, b2); - } - - /** - * Creates a new SimpleRegister instance. - * - * @return a SimpleRegister instance. - */ - public Register createRegister() { - return new SimpleRegister(); - } - - /** - * Returns a new Register instance with a given value. - * - * @param b1 the first byte. - * @param b2 the second byte. - * - * @return a Register instance. - */ - public Register createRegister(byte b1, byte b2) { - return new SimpleRegister(b1, b2); - } - - /** - * Returns a new InputRegister instance with a given value. - * - * @param value the value of the register as an int - * - * @return an InputRegister instance. - */ - public InputRegister createInputRegister(int value) { - return new SimpleInputRegister(value); - } - - /** - * Creates a new SimpleRegister instance. - * - * @param value initial value of the register - * @return a SimpleRegister instance. - */ - public Register createRegister(int value) { - return new SimpleRegister(value); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalIn.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalIn.java deleted file mode 100644 index beacb8e..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalIn.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining a digital input. - *

- * In Modbus terms this represents an - * input discrete, it is read only from - * the slave side. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface DigitalIn { - - /** - * Tests if this DigitalIn is set. - *

- * - * @return true if set, false otherwise. - */ - boolean isSet(); - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalOut.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalOut.java deleted file mode 100644 index e0dcb04..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/DigitalOut.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining a digital output. - *

- * In Modbus terms this represents a - * coil, which is read-write from slave and - * master or device side.
- * Therefor implementations have to be carefully - * designed for concurrency. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface DigitalOut { - - /** - * Tests if this DigitalOut is set. - *

- * - * @return true if set, false otherwise. - */ - boolean isSet(); - - /** - * Sets the state of this DigitalOut. - *

- * - * @param b true if to be set, false otherwise. - */ - void set(boolean b); - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/FIFO.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/FIFO.java deleted file mode 100644 index d5f1b72..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/FIFO.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Vector; - -/** - * @author Julie - * - * FIFO -- an abstraction of a Modbus FIFO, as supported by the - * READ FIFO command. - * - * The FIFO class is only intended to be used for testing purposes and does - * not reflect the actual behavior of a FIFO in a real Modbus device. In an - * actual Modbus device, the FIFO is mapped within a fixed address. - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class FIFO { - - private static final Logger logger = LoggerFactory.getLogger(FIFO.class); - - private int address; - private int registerCount; - private Vector registers; - - public FIFO(int address) { - this.address = address; - registerCount = 0; - registers = new Vector(); - } - - public synchronized int getRegisterCount() { - return registerCount; - } - - public synchronized Register[] getRegisters() { - Register result[] = new Register[registerCount + 1]; - - result[0] = new SimpleRegister(registerCount); - for (int i = 0; i < registerCount; i++) { - result[i + 1] = registers.get(i); - } - - return result; - } - - public synchronized void pushRegister(Register register) { - if (registerCount == 31) { - registers.remove(0); - } - else { - registerCount++; - } - - registers.add(new SimpleRegister(register.getValue())); - } - - public synchronized void resetRegisters() { - registers.removeAllElements(); - registerCount = 0; - } - - public int getAddress() { - return address; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/File.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/File.java deleted file mode 100644 index 4728706..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/File.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Julie - * - * File -- an abstraction of a Modbus File, as supported by the - * READ FILE RECORD and WRITE FILE RECORD commands. - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class File { - - private static final Logger logger = LoggerFactory.getLogger(File.class); - - private int fileNumber; - private int record_Count; - private Record records[]; - - public File(int fileNumber, int records) { - this.fileNumber = fileNumber; - record_Count = records; - this.records = new Record[records]; - } - - public int getFileNumber() { - return fileNumber; - } - - public int getRecordCount() { - return record_Count; - } - - public Record getRecord(int i) { - if (i < 0 || i >= record_Count) { - throw new IllegalAddressException(); - } - - return records[i]; - } - - public File setRecord(int i, Record record) { - if (i < 0 || i >= record_Count) { - throw new IllegalAddressException(); - } - - records[i] = record; - - return this; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/IllegalAddressException.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/IllegalAddressException.java deleted file mode 100644 index 79c19eb..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/IllegalAddressException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Class implementing an IllegalAddressException. This exception is - * thrown when a non-existant spot in the process image was addressed. - *

- * Note that this is a runtime exception, as it is similar to the - * IndexOutOfBoundsException - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class IllegalAddressException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * Constructs a new IllegalAddressException. - */ - public IllegalAddressException() { - } - - /** - * Constructs a new IllegalAddressException with the given message. - * - * @param message a message as String. - */ - public IllegalAddressException(String message) { - super(message); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/InputRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/InputRegister.java deleted file mode 100644 index eee394b..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/InputRegister.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining an input register. - *

- * This register is read only from the slave side. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface InputRegister { - - /** - * Returns the value of this InputRegister. The value is stored as - * int but should be treated like a 16-bit word. - * - * @return the value as int. - */ - int getValue(); - - /** - * Returns the content of this Register as unsigned 16-bit value - * (unsigned short). - * - * @return the content as unsigned short (int). - */ - int toUnsignedShort(); - - /** - * Returns the content of this Register as signed 16-bit value - * (short). - * - * @return the content as short. - */ - short toShort(); - - /** - * Returns the content of this Register as bytes. - * - * @return a byte[] with length 2. - */ - byte[] toBytes(); - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableDigitalOut.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableDigitalOut.java deleted file mode 100644 index 67b1d66..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableDigitalOut.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import com.ghgande.j2mod.modbus.util.Observable; - -/** - * Class implementing an observable digital output. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ObservableDigitalOut extends Observable implements DigitalOut { - - /** - * A boolean holding the state of this digital out. - */ - protected boolean set; - - /** - * Determine if the digital output is set. - * - * @return the boolean value of the digital output. - */ - public boolean isSet() { - return set; - } - - /** - * Set or clear the digital output. Will notify any registered - * observers. - */ - public void set(boolean b) { - set = b; - notifyObservers("value"); - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableRegister.java deleted file mode 100644 index 1722734..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ObservableRegister.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import com.ghgande.j2mod.modbus.util.Observable; - -/** - * Class implementing an observable register. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ObservableRegister extends Observable implements Register { - - /** - * The word holding the content of this register. - */ - protected short register; - - synchronized public int getValue() { - return register & 0xFFFF; - } - - public final int toUnsignedShort() { - return register & 0xFFFF; - } - - public final short toShort() { - return register; - } - - public synchronized byte[] toBytes() { - return new byte[]{(byte)(register >> 8), (byte)(register & 0xFF)}; - } - - public final synchronized void setValue(short s) { - register = s; - notifyObservers("value"); - } - - public final synchronized void setValue(byte[] bytes) { - if (bytes.length < 2) { - throw new IllegalArgumentException(); - } - else { - register = (short)(((short)((bytes[0] << 8))) | (((short)(bytes[1])) & 0xFF)); - notifyObservers("value"); - } - } - - public final synchronized void setValue(int v) { - register = (short)v; - notifyObservers("value"); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImage.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImage.java deleted file mode 100644 index 3da266c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImage.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining a process image in an object oriented manner. - *

- * The process image is understood as a shared memory area used form - * communication between slave and master or device side. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface ProcessImage { - - /** - * Returns a range of DigitalOut instances. - * - * @param offset the start offset. - * @param count the amount of DigitalOut from the offset. - * - * @return an array of DigitalOut instances. - * - * @throws IllegalAddressException if the range from offset to offset+count is non existant. - */ - DigitalOut[] getDigitalOutRange(int offset, int count) throws IllegalAddressException; - - /** - * Returns the DigitalOut instance at the given reference. - * - * @param ref the reference. - * - * @return the DigitalOut instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - DigitalOut getDigitalOut(int ref) throws IllegalAddressException; - - /** - * Returns the number of DigitalOut instances in this - * ProcessImage. - * - * @return the number of digital outs as int. - */ - int getDigitalOutCount(); - - /** - * Returns a range of DigitalIn instances. - * - * @param offset the start offset. - * @param count the amount of DigitalIn from the offset. - * - * @return an array of DigitalIn instances. - * - * @throws IllegalAddressException if the range from offset to offset+count is non existant. - */ - DigitalIn[] getDigitalInRange(int offset, int count) throws IllegalAddressException; - - /** - * Returns the DigitalIn instance at the given reference. - * - * @param ref the reference. - * - * @return the DigitalIn instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - DigitalIn getDigitalIn(int ref) throws IllegalAddressException; - - /** - * Returns the number of DigitalIn instances in this - * ProcessImage. - * - * @return the number of digital ins as int. - */ - int getDigitalInCount(); - - /** - * Returns a range of InputRegister instances. - * - * @param offset the start offset. - * @param count the amount of InputRegister from the offset. - * - * @return an array of InputRegister instances. - * - * @throws IllegalAddressException if the range from offset to offset+count is non existant. - */ - InputRegister[] getInputRegisterRange(int offset, int count) throws IllegalAddressException; - - /** - * Returns the InputRegister instance at the given reference. - * - * @param ref the reference. - * - * @return the InputRegister instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - InputRegister getInputRegister(int ref) throws IllegalAddressException; - - /** - * Returns the number of InputRegister instances in this - * ProcessImage. - * - *

- * This is not the same as the value of the highest addressable register. - * - * @return the number of input registers as int. - */ - int getInputRegisterCount(); - - /** - * Returns a range of Register instances. - * - * @param offset the start offset. - * @param count the amount of Register from the offset. - * - * @return an array of Register instances. - * - * @throws IllegalAddressException if the range from offset to offset+count is non existant. - */ - Register[] getRegisterRange(int offset, int count) throws IllegalAddressException; - - /** - * Returns the Register instance at the given reference. - *

- * - * @param ref the reference. - * - * @return the Register instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - Register getRegister(int ref) throws IllegalAddressException; - - /** - * Returns the number of Register instances in this - * ProcessImage. - * - *

- * This is not the same as the value of the highest addressable register. - * - * @return the number of registers as int. - */ - int getRegisterCount(); - - /** - * Returns the File instance at the given reference. - *

- * - * @param ref the reference. - * - * @return the File instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - File getFile(int ref) throws IllegalAddressException; - - /** - * Returns the File instance having the specified file number. - * - * @param ref The file number for the File object to be returned. - * - * @return the File instance having the given number. - * - * @throws IllegalAddressException if a File with the given number does not exist. - */ - File getFileByNumber(int ref) throws IllegalAddressException; - - /** - * Returns the number of File instances in this - * ProcessImage. - * - *

- * This is not the same as the value of the highest addressable register. - * - * @return the number of registers as int. - */ - int getFileCount(); - - /** - * Returns the FIFO instance in the list of all FIFO objects - * in this ProcessImage. - * - * @param ref the reference. - * - * @return the File instance at the given address. - * - * @throws IllegalAddressException if the reference is invalid. - */ - FIFO getFIFO(int ref) throws IllegalAddressException; - - /** - * Returns the FIFO instance having the specified base address. - * - * @param ref The address for the FIFO object to be returned. - * - * @return the FIFO instance having the given base address - * - * @throws IllegalAddressException if a File with the given number does not exist. - */ - FIFO getFIFOByAddress(int ref) throws IllegalAddressException; - - /** - * Returns the number of File instances in this - * ProcessImage. - * - *

- * This is not the same as the value of the highest addressable register. - * - * @return the number of registers as int. - */ - int getFIFOCount(); -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageFactory.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageFactory.java deleted file mode 100644 index 2e1cd80..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining the factory methods for - * the process image and it's elements. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface ProcessImageFactory { - - /** - * Returns a new ProcessImageImplementation instance. - * - * @return a ProcessImageImplementation instance. - */ - ProcessImageImplementation createProcessImageImplementation(); - - /** - * Returns a new DigitalIn instance. - * - * @return a DigitalIn instance. - */ - DigitalIn createDigitalIn(); - - /** - * Returns a new DigitalIn instance with the given state. - * - * @param state true if set, false otherwise. - * - * @return a DigitalIn instance. - */ - DigitalIn createDigitalIn(boolean state); - - /** - * Returns a new DigitalOut instance. - * - * @return a DigitalOut instance. - */ - DigitalOut createDigitalOut(); - - /** - * Returns a new DigitalOut instance with the - * given state. - * - * @param b true if set, false otherwise. - * - * @return a DigitalOut instance. - */ - DigitalOut createDigitalOut(boolean b); - - /** - * Returns a new InputRegister instance. - * - * @return an InputRegister instance. - */ - InputRegister createInputRegister(); - - /** - * Returns a new InputRegister instance with a - * given value. - * - * @param b1 the first byte. - * @param b2 the second byte. - * - * @return an InputRegister instance. - */ - InputRegister createInputRegister(byte b1, byte b2); - - /** - * Creates a new Register instance. - * - * @return a Register instance. - */ - Register createRegister(); - - /** - * Returns a new Register instance with a - * given value. - * - * @param b1 the first byte. - * @param b2 the second byte. - * - * @return a Register instance. - */ - Register createRegister(byte b1, byte b2); - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageImplementation.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageImplementation.java deleted file mode 100644 index b6a5da7..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/ProcessImageImplementation.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining implementation specific details of the - * ProcessImage, adding mechanisms for creating and modifying the - * actual "process image". - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface ProcessImageImplementation extends ProcessImage { - - /** - * Defines the set state (i.e. true) of a digital input or output. - */ - byte DIG_TRUE = 1; - /** - * Defines the unset state (i.e. false) of a digital input or output. - */ - byte DIG_FALSE = 0; - /** - * Defines the invalid (unset, neither true nor false) state of a digital - * input or output. - */ - byte DIG_INVALID = -1; - - /** - * Sets a new DigitalOut instance at the given reference. - * - * @param ref the reference as int. - * @param out the new DigitalOut instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setDigitalOut(int ref, DigitalOut out) throws IllegalAddressException; - - /** - * Adds a new DigitalOut instance. - * - * @param out the DigitalOut instance to be added. - */ - void addDigitalOut(DigitalOut out); - - /** - * Adds a new DigitalOut instance at the given reference. - * - * @param ref - the reference for the instance. - * @param out - the DigitalOut instance to be added. - */ - void addDigitalOut(int ref, DigitalOut out); - - /** - * Removes a given DigitalOut instance. - * - * @param out the DigitalOut instance to be removed. - */ - void removeDigitalOut(DigitalOut out); - - /** - * Sets a new DigitalIn instance at the given reference. - * - * @param ref the reference as int. - * @param di the new DigitalIn instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setDigitalIn(int ref, DigitalIn di) throws IllegalAddressException; - - /** - * Adds a new DigitalIn instance. - * - * @param di the DigitalIn instance to be added. - */ - void addDigitalIn(DigitalIn di); - - /** - * Adds a new DigitalIn instance at the given reference, possibly - * creating a hole between the last existing reference and the new object. - * - * @param ref - the reference for the new instance. - * @param di the DigitalIn instance to be added. - */ - void addDigitalIn(int ref, DigitalIn di); - - /** - * Removes a given DigitalIn instance. - * - * @param di the DigitalIn instance to be removed. - */ - void removeDigitalIn(DigitalIn di); - - /** - * Sets a new InputRegister instance at the given reference. - * - * @param ref the reference as int. - * @param reg the new InputRegister instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setInputRegister(int ref, InputRegister reg) throws IllegalAddressException; - - /** - * Adds a new InputRegister instance. - * - * @param reg the InputRegister instance to be added. - */ - void addInputRegister(InputRegister reg); - - /** - * Adds a new InputRegister instance, possibly - * creating a hole between the last existing reference and the new object. - * - * @param ref - The reference for the new instance. - * @param reg the InputRegister instance to be added. - */ - void addInputRegister(int ref, InputRegister reg); - - /** - * Removes a given InputRegister instance. - * - * @param reg the InputRegister instance to be removed. - */ - void removeInputRegister(InputRegister reg); - - /** - * Sets a new Register instance at the given reference. - * - * @param ref the reference as int. - * @param reg the new Register instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setRegister(int ref, Register reg) throws IllegalAddressException; - - /** - * Adds a new Register instance. - * - * @param reg the Register instance to be added. - */ - void addRegister(Register reg); - - /** - * Adds a new Register instance, possibly - * creating a hole between the last existing reference and the new object. - * - * @param ref - the reference for the new instance. - * @param reg the Register instance to be added. - */ - void addRegister(int ref, Register reg); - - /** - * Removes a given Register instance. - * - * @param reg the Register instance to be removed. - */ - void removeRegister(Register reg); - - /** - * Sets a new File instance at the given reference. - * - * @param ref the reference as int. - * @param reg the new File instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setFile(int ref, File reg) throws IllegalAddressException; - - /** - * Adds a new File instance. - * - * @param reg the File instance to be added. - */ - void addFile(File reg); - - /** - * Adds a new File instance, possibly - * creating a hole between the last existing reference and the new object. - * - * @param ref - the reference for the new isntance. - * @param reg the File instance to be added. - */ - void addFile(int ref, File reg); - - /** - * Removes a given File instance. - * - * @param reg the File instance to be removed. - */ - void removeFile(File reg); - - /** - * Sets a new FIFO instance at the given reference. - * - * @param ref the reference as int. - * @param reg the new FIFO instance to be set. - * - * @throws IllegalAddressException if the reference is invalid. - */ - void setFIFO(int ref, FIFO reg) throws IllegalAddressException; - - /** - * Adds a new FIFO instance. - * - * @param reg the FIFO instance to be added. - */ - void addFIFO(FIFO reg); - - /** - * Adds a new FIFO instance, possibly - * creating a hole between the last existing reference and the new object. - * - * @param ref - the reference for the new instance. - * @param reg the FIFO instance to be added. - */ - void addFIFO(int ref, FIFO reg); - - /** - * Removes a given FIFO instance. - * - * @param reg the FIFO instance to be removed. - */ - void removeFIFO(FIFO reg); -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Record.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Record.java deleted file mode 100644 index 924988b..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Record.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Julie - * - * File -- an abstraction of a Modbus Record, as supported by the - * READ FILE RECORD and WRITE FILE RECORD commands. - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class Record { - - private static final Logger logger = LoggerFactory.getLogger(Record.class); - - private int recordNumber; - private int registerCount; - private Register registers[]; - - public Record(int recordNumber, int registers) { - this.recordNumber = recordNumber; - registerCount = registers; - this.registers = new Register[registers]; - - for (int i = 0; i < registerCount; i++) { - this.registers[i] = new SimpleRegister(0); - } - } - - public int getRecordNumber() { - return recordNumber; - } - - public int getRegisterCount() { - return registerCount; - } - - public Register getRegister(int register) { - if (register < 0 || register >= registerCount) { - throw new IllegalAddressException(); - } - - return registers[register]; - } - - public Record setRegister(int ref, Register register) { - if (ref < 0 || ref >= registerCount) { - throw new IllegalAddressException(); - } - - registers[ref] = register; - - return this; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Register.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Register.java deleted file mode 100644 index 31dc153..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/Register.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Interface defining a register. - * - *

- * A register is read-write from slave and master or device side. Therefore - * implementations have to be carefully designed for concurrency. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface Register extends InputRegister { - - /** - * Sets the content of this Register from the given unsigned 16-bit - * value (unsigned short). - * - * @param v the value as unsigned short (int). - */ - void setValue(int v); - - /** - * Sets the content of this register from the given signed 16-bit value - * (short). - * - * @param s the value as short. - */ - void setValue(short s); - - /** - * Sets the content of this register from the given raw bytes. - * - * @param bytes the raw data as byte[]. - */ - void setValue(byte[] bytes); -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalIn.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalIn.java deleted file mode 100644 index fdbca84..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalIn.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Class implementing a simple DigitalIn. - *

- * The set method is synchronized, which ensures atomic - * access, but no specific access order. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SimpleDigitalIn implements DigitalIn { - - /** - * Field for the digital in state. - */ - protected boolean set = false; - - /** - * Constructs a new SimpleDigitalIn instance. - */ - public SimpleDigitalIn() { - } - - /** - * Constructs a new SimpleDigitalIn instance - * with a given valid state. - * - * @param b true if to be set, false otherwise. - */ - public SimpleDigitalIn(boolean b) { - set(b); - } - - public boolean isSet() { - return set; - } - - /** - * Sets the state of this SimpleDigitalIn. - * This method should only be used from master/device - * side. - * - * @param b true if to be set, false otherwise. - */ - public synchronized void set(boolean b) { - set = b; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalOut.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalOut.java deleted file mode 100644 index b88e690..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleDigitalOut.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Class implementing a simple DigitalOut. - *

- * The set method is synchronized, which ensures atomic - * access, but no specific access order. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SimpleDigitalOut implements DigitalOut { - - /** - * Field for the digital out state. - */ - protected boolean set; - - /** - * Constructs a new SimpleDigitalOut instance. - * It's state will be invalid. - */ - public SimpleDigitalOut() { - } - - /** - * Constructs a new SimpleDigitalOut instance - * with the given state. - * - * @param b true if set, false otherwise. - */ - public SimpleDigitalOut(boolean b) { - set(b); - } - - public boolean isSet() { - return set; - } - - public synchronized void set(boolean b) { - set = b; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleInputRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleInputRegister.java deleted file mode 100644 index 96cce0c..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleInputRegister.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Class implementing a simple InputRegister. - *

- * The setValue() method is synchronized, which ensures atomic access, * but no specific access order. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SimpleInputRegister extends SynchronizedAbstractRegister implements InputRegister { - - /** - * Constructs a new SimpleInputRegister instance. It's state will - * be invalid. - */ - public SimpleInputRegister() { - } - - /** - * Constructs a new SimpleInputRegister instance. - * - * @param b1 the first (hi) byte of the word. - * @param b2 the second (low) byte of the word. - */ - public SimpleInputRegister(byte b1, byte b2) { - register[0] = b1; - register[1] = b2; - } - - /** - * Constructs a new SimpleInputRegister instance with the given - * value. - * - * @param value the value of this SimpleInputRegister as int - * . - */ - public SimpleInputRegister(int value) { - setValue(value); - }// constructor(int) - - public String toString() { - if (register == null) { - return "invalid"; - } - - return getValue() + ""; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleProcessImage.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleProcessImage.java deleted file mode 100644 index 69ef723..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleProcessImage.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -import java.util.Vector; - -/** - * Class implementing a simple process image to be able to run unit tests or - * handle simple cases. - * - *

- * The image has a simple linear address space for, analog, digital and file - * objects. Holes may be created by adding a object with a reference after the - * last object reference of that type. - * - * @author Dieter Wimberger - * @author Julie Added support for files of records. - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SimpleProcessImage implements ProcessImageImplementation { - - // instance attributes - protected final Vector digitalIns = new Vector(); - protected final Vector digitalOuts = new Vector(); - protected final Vector inputRegisters = new Vector(); - protected final Vector registers = new Vector(); - protected final Vector files = new Vector(); - protected final Vector fifos = new Vector(); - protected boolean locked = false; - protected int unitID = 0; - - /** - * Constructs a new SimpleProcessImage instance. - */ - public SimpleProcessImage() { - } - - /** - * Constructs a new SimpleProcessImage instance having a - * (potentially) non-zero unit ID. - * @param unit Unit ID of this image - */ - public SimpleProcessImage(int unit) { - unitID = unit; - } - - /** - * The process image is locked to prevent changes. - * - * @return whether or not the process image is locked. - */ - public synchronized boolean isLocked() { - return locked; - } - - /** - * setLocked -- lock or unlock the process image. It is an error (false - * return value) to attempt to lock the process image when it is already - * locked. - * - *

- * Compatability Note: jamod did not enforce this restriction, so it is - * being handled in a way which is backwards compatible. If you wish to - * determine if you acquired the lock, check the return value. If your code - * is still based on the jamod paradigm, you will ignore the return value - * and your code will function as before. - *

- * @param locked True if the image is to be locked - * @return setting lock succeded - */ - public synchronized boolean setLocked(boolean locked) { - if (this.locked && locked) { - return false; - } - - this.locked = locked; - return true; - } - - public int getUnitID() { - return unitID; - } - - public DigitalOut[] getDigitalOutRange(int ref, int count) { - // ensure valid reference range - if (ref < 0 || ref + count > digitalOuts.size()) { - throw new IllegalAddressException(); - } - else { - DigitalOut[] douts = new DigitalOut[count]; - for (int i = 0; i < douts.length; i++) { - douts[i] = getDigitalOut(ref + i); - } - return douts; - } - } - - public DigitalOut getDigitalOut(int ref) throws IllegalAddressException { - try { - DigitalOut result = digitalOuts.elementAt(ref); - if (result == null) { - throw new IllegalAddressException(); - } - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public int getDigitalOutCount() { - return digitalOuts.size(); - } - - public DigitalIn[] getDigitalInRange(int ref, int count) { - // ensure valid reference range - if (ref < 0 || ref + count > digitalIns.size()) { - throw new IllegalAddressException(); - } - else { - DigitalIn[] dins = new DigitalIn[count]; - for (int i = 0; i < dins.length; i++) { - dins[i] = getDigitalIn(ref + i); - } - return dins; - } - } - - public DigitalIn getDigitalIn(int ref) throws IllegalAddressException { - try { - DigitalIn result = digitalIns.elementAt(ref); - if (result == null) { - throw new IllegalAddressException(); - } - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public int getDigitalInCount() { - return digitalIns.size(); - } - - public InputRegister[] getInputRegisterRange(int ref, int count) { - // ensure valid reference range - if (ref < 0 || ref + count > inputRegisters.size()) { - throw new IllegalAddressException(); - } - - InputRegister[] iregs = new InputRegister[count]; - for (int i = 0; i < iregs.length; i++) { - iregs[i] = getInputRegister(ref + i); - } - - return iregs; - } - - public InputRegister getInputRegister(int ref) throws IllegalAddressException { - try { - InputRegister result = inputRegisters.elementAt(ref); - if (result == null) { - throw new IllegalAddressException(); - } - - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public int getInputRegisterCount() { - return inputRegisters.size(); - } - - public Register[] getRegisterRange(int ref, int count) { - if (ref < 0 || ref + count > registers.size()) { - throw new IllegalAddressException(); - } - else { - Register[] iregs = new Register[count]; - for (int i = 0; i < iregs.length; i++) { - iregs[i] = getRegister(ref + i); - } - return iregs; - } - } - - public Register getRegister(int ref) throws IllegalAddressException { - try { - Register result = registers.elementAt(ref); - if (result == null) { - throw new IllegalAddressException(); - } - - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public int getRegisterCount() { - return registers.size(); - } - - public File getFile(int fileNumber) { - try { - File result = files.elementAt(fileNumber); - if (result == null) { - throw new IllegalAddressException(); - } - - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public File getFileByNumber(int ref) { - if (ref < 0 || ref >= 10000 || files == null) { - throw new IllegalAddressException(); - } - - synchronized (files) { - for (File file : files) { - if (file.getFileNumber() == ref) { - return file; - } - } - } - - throw new IllegalAddressException(); - } - - public int getFileCount() { - return files.size(); - } - - public FIFO getFIFO(int fifoNumber) { - try { - FIFO result = fifos.elementAt(fifoNumber); - if (result == null) { - throw new IllegalAddressException(); - } - - return result; - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - - public FIFO getFIFOByAddress(int ref) { - for (FIFO fifo : fifos) { - if (fifo.getAddress() == ref) { - return fifo; - } - } - - return null; - } - - public int getFIFOCount() { - if (fifos == null) { - return 0; - } - - return fifos.size(); - } - - public void setDigitalOut(int ref, DigitalOut _do) throws IllegalAddressException { - if (!isLocked()) { - try { - if (digitalOuts.get(ref) == null) { - throw new IllegalAddressException(); - } - digitalOuts.setElementAt(_do, ref); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addDigitalOut(DigitalOut _do) { - if (!isLocked()) { - digitalOuts.addElement(_do); - } - } - - public void addDigitalOut(int ref, DigitalOut dout) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (digitalOuts) { - if (ref < digitalOuts.size()) { - digitalOuts.setElementAt(dout, ref); - return; - } - digitalOuts.setSize(ref + 1); - digitalOuts.setElementAt(dout, ref); - } - } - } - - public void removeDigitalOut(DigitalOut _do) { - if (!isLocked()) { - digitalOuts.removeElement(_do); - } - } - - public void setDigitalIn(int ref, DigitalIn di) throws IllegalAddressException { - if (!isLocked()) { - try { - if (digitalIns.get(ref) == null) { - throw new IllegalAddressException(); - } - digitalIns.setElementAt(di, ref); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addDigitalIn(DigitalIn di) { - if (!isLocked()) { - digitalIns.addElement(di); - } - } - - public void addDigitalIn(int ref, DigitalIn d1) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (digitalIns) { - if (ref < digitalIns.size()) { - digitalIns.setElementAt(d1, ref); - return; - } - digitalIns.setSize(ref + 1); - digitalIns.setElementAt(d1, ref); - } - } - } - - public void removeDigitalIn(DigitalIn di) { - if (!isLocked()) { - digitalIns.removeElement(di); - } - } - - public void setInputRegister(int ref, InputRegister reg) throws IllegalAddressException { - if (!isLocked()) { - try { - if (inputRegisters.get(ref) == null) { - throw new IllegalAddressException(); - } - - inputRegisters.setElementAt(reg, ref); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addInputRegister(InputRegister reg) { - if (!isLocked()) { - inputRegisters.addElement(reg); - } - } - - public void addInputRegister(int ref, InputRegister inReg) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (inputRegisters) { - if (ref < inputRegisters.size()) { - inputRegisters.setElementAt(inReg, ref); - return; - } - inputRegisters.setSize(ref + 1); - inputRegisters.setElementAt(inReg, ref); - } - } - } - - public void removeInputRegister(InputRegister reg) { - if (!isLocked()) { - inputRegisters.removeElement(reg); - } - } - - public void setRegister(int ref, Register reg) throws IllegalAddressException { - if (!isLocked()) { - try { - if (registers.get(ref) == null) { - throw new IllegalAddressException(); - } - - registers.setElementAt(reg, ref); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addRegister(Register reg) { - if (!isLocked()) { - registers.addElement(reg); - } - } - - public void addRegister(int ref, Register reg) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (registers) { - if (ref < registers.size()) { - registers.setElementAt(reg, ref); - return; - } - registers.setSize(ref + 1); - registers.setElementAt(reg, ref); - } - } - } - - public void removeRegister(Register reg) { - if (!isLocked()) { - registers.removeElement(reg); - } - } - - public void setFile(int fileNumber, File file) { - if (!isLocked()) { - try { - if (files.get(fileNumber) == null) { - throw new IllegalAddressException(); - } - - files.setElementAt(file, fileNumber); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addFile(File newFile) { - if (!isLocked()) { - files.add(newFile); - } - } - - public void addFile(int ref, File newFile) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (files) { - if (ref < files.size()) { - files.setElementAt(newFile, ref); - return; - } - files.setSize(ref + 1); - files.setElementAt(newFile, ref); - } - } - } - - public void removeFile(File oldFile) { - if (!isLocked()) { - files.removeElement(oldFile); - } - } - - public void setFIFO(int fifoNumber, FIFO fifo) { - if (!isLocked()) { - try { - if (fifos.get(fifoNumber) == null) { - throw new IllegalAddressException(); - } - - fifos.setElementAt(fifo, fifoNumber); - } - catch (IndexOutOfBoundsException ex) { - throw new IllegalAddressException(); - } - } - } - - public void addFIFO(FIFO fifo) { - if (!isLocked()) { - fifos.add(fifo); - } - } - - public void addFIFO(int ref, FIFO newFIFO) { - if (ref < 0 || ref >= 65536) { - throw new IllegalArgumentException(); - } - - if (!isLocked()) { - synchronized (fifos) { - if (ref < fifos.size()) { - fifos.setElementAt(newFIFO, ref); - return; - } - fifos.setSize(ref + 1); - fifos.setElementAt(newFIFO, ref); - } - } - } - - public void removeFIFO(FIFO oldFIFO) { - if (!isLocked()) { - fifos.removeElement(oldFIFO); - } - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleRegister.java deleted file mode 100644 index 91e6df8..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SimpleRegister.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Class implementing a simple Register. - *

- * The setValue() method is synchronized, which ensures atomic access, * but no specific access order. - * - * @author Dieter Wimberger - * @author Julie Haugh - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SimpleRegister extends SynchronizedAbstractRegister implements - Register { - - /** - * Constructs a new SimpleRegister instance. - * - * @param b1 the first (hi) byte of the word. - * @param b2 the second (low) byte of the word. - */ - public SimpleRegister(byte b1, byte b2) { - register[0] = b1; - register[1] = b2; - } - - /** - * Constructs a new SimpleRegister instance with the given value. - * - * @param value the value of this SimpleRegister as int. - */ - public SimpleRegister(int value) { - setValue(value); - } - - /** - * Constructs a new SimpleRegister instance. It's state will be - * invalid. - * - * Attempting to access this register will result in an - * IllegalAddressException(). It may be used to create "holes" in a Modbus - * register map. - */ - public SimpleRegister() { - register = null; - } - - public String toString() { - if (register == null) { - return "invalid"; - } - - return getValue() + ""; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SynchronizedAbstractRegister.java b/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SynchronizedAbstractRegister.java deleted file mode 100644 index ab6f5ae..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/procimg/SynchronizedAbstractRegister.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.procimg; - -/** - * Abstract class with synchronized register operations. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public abstract class SynchronizedAbstractRegister implements Register { - - /** - * The word (byte[2]) holding the state of this register. - * - * Note that a superclass may set register to null to create a - * gap in a Modbus map. - */ - protected byte[] register = new byte[2]; - - synchronized public int getValue() { - if (register == null) { - throw new IllegalAddressException(); - } - - return ((register[0] & 0xff) << 8 | (register[1] & 0xff)); - } - - public final int toUnsignedShort() { - if (register == null) { - throw new IllegalAddressException(); - } - - return ((register[0] & 0xff) << 8 | (register[1] & 0xff)); - } - - public final short toShort() { - if (register == null) { - throw new IllegalAddressException(); - } - - return (short)((register[0] << 8) | (register[1] & 0xff)); - } - - public synchronized byte[] toBytes() { - byte[] dest = new byte[register.length]; - System.arraycopy(register, 0, dest, 0, dest.length); - return dest; - } - - public final synchronized void setValue(short s) { - if (register == null) { - throw new IllegalAddressException(); - } - - register[0] = (byte)(0xff & (s >> 8)); - register[1] = (byte)(0xff & s); - } - - public final synchronized void setValue(byte[] bytes) { - if (bytes.length < 2) { - throw new IllegalArgumentException(); - } - else { - if (register == null) { - throw new IllegalAddressException(); - } - - register[0] = bytes[0]; - register[1] = bytes[1]; - } - } - - public final synchronized void setValue(int v) { - if (register == null) { - throw new IllegalAddressException(); - } - - register[0] = (byte)(0xff & (v >> 8)); - register[1] = (byte)(0xff & v); - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlave.java b/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlave.java deleted file mode 100644 index 55e94ce..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlave.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.slave; - -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.net.ModbusTCPListener; -import com.ghgande.j2mod.modbus.net.ModbusUDPListener; -import com.ghgande.j2mod.modbus.procimg.ProcessImage; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import com.ghgande.j2mod.modbus.util.SerialParameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.util.HashMap; -import java.util.Map; - -/** - * Class that implements a wrapper around a Slave Listener - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusSlave { - - private static final Logger logger = LoggerFactory.getLogger(ModbusSlave.class); - - private ModbusSlaveType type; - private int port; - private SerialParameters serialParams; - private AbstractModbusListener listener; - private boolean isRunning; - private Thread listenerThread; - - private Map processImages = new HashMap(); - - /** - * Creates a TCP modbus slave - * - * @param port Port to listen on if IP type - * @param poolSize Pool size for TCP slaves - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws ModbusException If a problem occurs e.g. port already in use - */ - protected ModbusSlave(int port, int poolSize, boolean useRtuOverTcp) throws ModbusException { - this(ModbusSlaveType.TCP, null, port, poolSize, null, useRtuOverTcp); - } - - /** - * Creates a TCP modbus slave - * - * @param address IP address to listen on - * @param port Port to listen on if IP type - * @param poolSize Pool size for TCP slaves - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws ModbusException If a problem occurs e.g. port already in use - */ - protected ModbusSlave(InetAddress address, int port, int poolSize, boolean useRtuOverTcp) throws ModbusException { - this(ModbusSlaveType.TCP, address, port, poolSize, null, useRtuOverTcp); - } - - /** - * Creates a UDP modbus slave - * - * @param port Port to listen on if IP type - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws ModbusException If a problem occurs e.g. port already in use - */ - protected ModbusSlave(int port, boolean useRtuOverTcp) throws ModbusException { - this(ModbusSlaveType.UDP, null, port, 0, null, useRtuOverTcp); - } - - /** - * Creates a UDP modbus slave - * - * @param address IP address to listen on - * @param port Port to listen on if IP type - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws ModbusException If a problem occurs e.g. port already in use - */ - protected ModbusSlave(InetAddress address, int port, boolean useRtuOverTcp) throws ModbusException { - this(ModbusSlaveType.UDP, address, port, 0, null, useRtuOverTcp); - } - - /** - * Creates a serial modbus slave - * - * @param serialParams Serial parameters for serial type slaves - * @throws ModbusException If a problem occurs e.g. port already in use - */ - protected ModbusSlave(SerialParameters serialParams) throws ModbusException { - this(ModbusSlaveType.SERIAL, null, 0, 0, serialParams, false); - } - - /** - * Creates an appropriate type of listener - * - * @param type Type of slave to create - * @param address IP address to listen on - * @param port Port to listen on if IP type - * @param poolSize Pool size for TCP slaves - * @param serialParams Serial parameters for serial type slaves - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @throws ModbusException If a problem occurs e.g. port already in use - */ - private ModbusSlave(ModbusSlaveType type, InetAddress address, int port, int poolSize, SerialParameters serialParams, boolean useRtuOverTcp) throws ModbusException { - this.type = type == null ? ModbusSlaveType.TCP : type; - this.port = port; - this.serialParams = serialParams; - - // Create the listener - - logger.debug("Creating {} listener", this.type.toString()); - if (this.type.is(ModbusSlaveType.UDP)) { - listener = new ModbusUDPListener(); - } - else if (this.type.is(ModbusSlaveType.TCP)) { - listener = new ModbusTCPListener(poolSize, useRtuOverTcp); - } - else { - // listener = new ModbusSerialListener(serialParams); - } - - listener.setListening(true); - listener.setAddress(address); - listener.setPort(port); - listener.setTimeout(0); - } - - /** - * Returns the type of this slave - * - * @return Type of slave - */ - public ModbusSlaveType getType() { - return type; - } - - /** - * Returns the port that this IP slave is listening on - * - * @return Port being listened on if TCP or UDP - */ - public int getPort() { - return port; - } - - /** - * Returns the process image for the given Unit ID - * - * @param unitId Unit ID of the associated image - * @return Process image - */ - public ProcessImage getProcessImage(int unitId) { - return processImages.get(unitId); - } - - /** - * Removes the process image for the given Unit ID - * - * @param unitId Unit ID of the associated image - * @return Process image - */ - public ProcessImage removeProcessImage(int unitId) { - return processImages.remove(unitId); - } - - /** - * Adds a process image for the given Unit ID - * - * @param unitId Unit ID to associate with this image - * @param processImage Process image to add - * @return Process image - */ - public ProcessImage addProcessImage(int unitId, ProcessImage processImage) { - return processImages.put(unitId, processImage); - } - - /** - * Returns the serial parameters of this slave if it is a Serial type - * - * @return Serial parameters - */ - public SerialParameters getSerialParams() { - return serialParams; - } - - /** - * Opens the listener to service requests - * - * @throws ModbusException If we cannot listen - */ - public void open() throws ModbusException { - - // Start the listener if it isn' already running - - if (!isRunning) { - try { - listenerThread = new Thread(listener); - listenerThread.start(); - isRunning = true; - } - catch (Exception x) { - closeListener(); - throw new ModbusException(x.getMessage()); - } - } - } - - /** - * Convenience method for closing this port and removing it from the running list - simply - * calls ModbusSlaveFactory.close(this) - */ - public void close() { - ModbusSlaveFactory.close(this); - } - - /** - * Returns the last error accrued by the listener - * - * @return Error if there is one - */ - public String getError() { - return listener != null ? listener.getError() : null; - } - - /** - * Returns the listener used for this port - * - * @return Listener - */ - protected AbstractModbusListener getListener() { - return listener; - } - - /** - * Closes the listener of this slave - */ - @SuppressWarnings("deprecation") - void closeListener() { - if (listener != null && listener.isListening()) { - listener.stop(); - - // Wait until the listener says it has stopped, but don't wait forever - int count = 0; - while (listenerThread != null && listenerThread.isAlive() && count < 50) { - ModbusUtil.sleep(100); - count++; - } - // If the listener is still not stopped, kill the thread - if (listenerThread != null && listenerThread.isAlive()) { - listenerThread.stop(); - } - listenerThread = null; - } - isRunning = false; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveFactory.java b/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveFactory.java deleted file mode 100644 index d8ad31a..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveFactory.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.slave; - -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.net.AbstractModbusListener; -import com.ghgande.j2mod.modbus.util.ModbusUtil; -import com.ghgande.j2mod.modbus.util.SerialParameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -/** - * This is a factory class that allows users to easily create and manage slaves.
- * Each slave is uniquely identified by the port it is listening on, irrespective of if - * the socket type (TCP, UDP or Serial) - * - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ModbusSlaveFactory { - - private static final Logger logger = LoggerFactory.getLogger(ModbusSlaveFactory.class); - private static Map slaves = new HashMap(); - - /** - * Creates a TCP modbus slave or returns the one already allocated to this port - * - * @param port Port to listen on - * @param poolSize Pool size of listener threads - * @return new or existing TCP modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createTCPSlave(int port, int poolSize) throws ModbusException { - return createTCPSlave(port, poolSize, false); - } - - /** - * Creates a TCP modbus slave or returns the one already allocated to this port - * - * @param port Port to listen on - * @param poolSize Pool size of listener threads - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @return new or existing TCP modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createTCPSlave(int port, int poolSize, boolean useRtuOverTcp) throws ModbusException { - return ModbusSlaveFactory.createTCPSlave(null, port, poolSize, useRtuOverTcp); - } - - /** - * Creates a TCP modbus slave or returns the one already allocated to this port - * - * @param address IP address to listen on - * @param port Port to listen on - * @param poolSize Pool size of listener threads - * @param useRtuOverTcp True if the RTU protocol should be used over TCP - * @return new or existing TCP modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createTCPSlave(InetAddress address, int port, int poolSize, boolean useRtuOverTcp) throws ModbusException { - String key = ModbusSlaveType.TCP.getKey(port); - if (slaves.containsKey(key)) { - return slaves.get(key); - } - else { - ModbusSlave slave = new ModbusSlave(address, port, poolSize, useRtuOverTcp); - slaves.put(key, slave); - return slave; - } - } - - /** - * Creates a UDP modbus slave or returns the one already allocated to this port - * - * @param port Port to listen on - * @return new or existing UDP modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createUDPSlave(int port) throws ModbusException { - return createUDPSlave(null, port); - } - - /** - * Creates a UDP modbus slave or returns the one already allocated to this port - * - * @param address IP address to listen on - * @param port Port to listen on - * @return new or existing UDP modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createUDPSlave(InetAddress address, int port) throws ModbusException { - String key = ModbusSlaveType.UDP.getKey(port); - if (slaves.containsKey(key)) { - return slaves.get(key); - } - else { - ModbusSlave slave = new ModbusSlave(address, port, false); - slaves.put(key, slave); - return slave; - } - } - - /** - * Creates a serial modbus slave or returns the one already allocated to this port - * - * @param serialParams Serial parameters for serial type slaves - * @return new or existing Serial modbus slave associated with the port - * - * @throws ModbusException If a problem occurs e.g. port already in use - */ - public static synchronized ModbusSlave createSerialSlave(SerialParameters serialParams) throws ModbusException { - ModbusSlave slave = null; - if (serialParams == null) { - throw new ModbusException("Serial parameters are null"); - } - else if (ModbusUtil.isBlank(serialParams.getPortName())) { - throw new ModbusException("Serial port name is empty"); - } - - // If we have a slave already assigned to this port - if (slaves.containsKey(serialParams.getPortName())) { - slave = slaves.get(serialParams.getPortName()); - - // Check if any of the parameters have changed - if (!serialParams.toString().equals(slave.getSerialParams().toString())) { - close(slave); - slave = null; - } - } - - // If we don;t have a slave, create one - if (slave == null) { - slave = new ModbusSlave(serialParams); - slaves.put(serialParams.getPortName(), slave); - return slave; - } - return slave; - } - - /** - * Closes this slave and removes it from the running list - * - * @param slave Slave to remove - */ - public static synchronized void close(ModbusSlave slave) { - if (slave != null) { - slave.closeListener(); - slaves.remove(slave.getType().getKey(slave.getPort())); - } - } - - /** - * Closes all slaves and removes them from the running list - */ - public static synchronized void close() { - for (ModbusSlave slave : new ArrayList(slaves.values())) { - slave.close(); - } - } - - /** - * Returns the running slave listening on the given IP port - * - * @param port Port to check for running slave - * @return Null or ModbusSlave - */ - public static ModbusSlave getSlave(int port) { - return slaves.get(port + ""); - } - - /** - * Returns the running slave listening on the given serial port - * - * @param port Port to check for running slave - * @return Null or ModbusSlave - */ - public static ModbusSlave getSlave(String port) { - return ModbusUtil.isBlank(port) ? null : slaves.get(port); - } - - /** - * Returns the running slave that utilises the give listener - * - * @param listener Listener used for this slave - * @return Null or ModbusSlave - */ - public static synchronized ModbusSlave getSlave(AbstractModbusListener listener) { - for (ModbusSlave slave : slaves.values()) { - if (slave.getListener().equals(listener)) { - return slave; - } - } - return null; - } - -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveType.java b/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveType.java deleted file mode 100644 index c993d15..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/slave/ModbusSlaveType.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.slave; - -import com.ghgande.j2mod.modbus.util.ModbusUtil; - -/** - * Descibes the types of Modbus Slaves - */ -public enum ModbusSlaveType { - TCP, UDP, SERIAL; - - /** - * Returns true if this type is one of those listed - * - * @param types Array of types to check for - * @return True if this is one of the array - */ - public boolean is(ModbusSlaveType... types) { - if (!ModbusUtil.isBlank(types)) { - for (ModbusSlaveType type : types) { - if (equals(type)) { - return true; - } - } - } - return false; - } - - /** - * Returns a unique key for this port and type - * - * @param port Port number - * @return Unique key - */ - public String getKey(int port) { - return toString() + port; - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/BitVector.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/BitVector.java deleted file mode 100644 index ff82cf9..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/BitVector.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class that implements a collection for - * bits, storing them packed into bytes. - * Per default the access operations will index from - * the LSB (rightmost) bit. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class BitVector { - - private static final Logger logger = LoggerFactory.getLogger(BitVector.class); - private static final int[] ODD_OFFSETS = {-1, -3, -5, -7}; - private static final int[] STRAIGHT_OFFSETS = {7, 5, 3, 1}; - //instance attributes - private int size; - private byte[] data; - private boolean MSBAccess = false; - - /** - * Constructs a new BitVector instance - * with a given size. - *

- * - * @param size the number of bits the BitVector - * should be able to hold. - */ - public BitVector(int size) { - //store bits - this.size = size; - - //calculate size in bytes - if ((size % 8) > 0) { - size = (size / 8) + 1; - } - else { - size = (size / 8); - } - data = new byte[size]; - } - - /** - * Factory method for creating a BitVector instance - * wrapping the given byte data. - * - * @param data a byte[] containing packed bits. - * @param size Size to set the bit vector to - * - * @return the newly created BitVector instance. - */ - public static BitVector createBitVector(byte[] data, int size) { - BitVector bv = new BitVector(data.length * 8); - bv.setBytes(data); - bv.size = size; - return bv; - } - - /** - * Factory method for creating a BitVector instance - * wrapping the given byte data. - * - * @param data a byte[] containing packed bits. - * - * @return the newly created BitVector instance. - */ - public static BitVector createBitVector(byte[] data) { - BitVector bv = new BitVector(data.length * 8); - bv.setBytes(data); - return bv; - } - - public static void main(String[] args) { - BitVector test = new BitVector(24); - logger.debug(test.isLSBAccess() + ""); - test.setBit(7, true); - logger.debug(test.getBit(7) + ""); - test.toggleAccess(true); - logger.debug(test.getBit(7) + ""); - - test.toggleAccess(true); - test.setBit(6, true); - test.setBit(3, true); - test.setBit(2, true); - - test.setBit(0, true); - test.setBit(8, true); - test.setBit(10, true); - - logger.debug(test.toString()); - test.toggleAccess(true); - logger.debug(test.toString()); - test.toggleAccess(true); - logger.debug(test.toString()); - - logger.debug(ModbusUtil.toHex(test.getBytes())); - } - - /** - * Toggles the flag deciding whether the LSB - * or the MSB of the byte corresponds to the - * first bit (index=0). - * - * @param b true if LSB=0 up to MSB=7, false otherwise. - */ - public void toggleAccess(boolean b) { - MSBAccess = !MSBAccess; - } - - /** - * Tests if this BitVector has - * the LSB (rightmost) as the first bit - * (i.e. at index 0). - * - * @return true if LSB=0 up to MSB=7, false otherwise. - */ - public boolean isLSBAccess() { - return !MSBAccess; - } - - /** - * Tests if this BitVector has - * the MSB (leftmost) as the first bit - * (i.e. at index 0). - * - * @return true if LSB=0 up to MSB=7, false otherwise. - */ - public boolean isMSBAccess() { - return MSBAccess; - } - - /** - * Returns the byte[] which is used to store - * the bits of this BitVector. - *

- * - * @return the byte[] used to store the bits. - */ - public synchronized final byte[] getBytes() { - byte[] dest = new byte[data.length]; - System.arraycopy(data, 0, dest, 0, dest.length); - return dest; - } - - /** - * Sets the byte[] which stores - * the bits of this BitVector. - *

- * - * @param data a byte[]. - */ - public final void setBytes(byte[] data) { - System.arraycopy(data, 0, this.data, 0, data.length); - } - - /** - * Sets the byte[] which stores - * the bits of this BitVector. - *

- * - * @param data a byte[]. - * @param size Size to set the bit vector to - */ - public final void setBytes(byte[] data, int size) { - System.arraycopy(data, 0, this.data, 0, data.length); - this.size = size; - } - - /** - * Returns the state of the bit at the given index of this - * BitVector. - *

- * - * @param index the index of the bit to be returned. - * - * @return true if the bit at the specified index is set, - * false otherwise. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public final boolean getBit(int index) throws IndexOutOfBoundsException { - index = translateIndex(index); - logger.debug("Get bit #{}", index); - return ((data[byteIndex(index)] - & (0x01 << bitIndex(index))) != 0 - ); - } - - /** - * Sets the state of the bit at the given index of - * this BitVector. - *

- * - * @param index the index of the bit to be set. - * @param b true if the bit should be set, false if it should be reset. - * - * @throws IndexOutOfBoundsException if the index is out of bounds. - */ - public final void setBit(int index, boolean b) throws IndexOutOfBoundsException { - index = translateIndex(index); - logger.debug("Set bit #{}", index); - int value = ((b) ? 1 : 0); - int byteNum = byteIndex(index); - int bitNum = bitIndex(index); - data[byteNum] = (byte)((data[byteNum] & ~(0x01 << bitNum)) - | ((value & 0x01) << bitNum) - ); - } - - /** - * Returns the number of bits in this BitVector - * as int. - *

- * - * @return the number of bits in this BitVector. - */ - public final int size() { - return size; - } - - /** - * Forces the number of bits in this BitVector. - * - * @param size Size to set the bit vector to - * - * @throws IllegalArgumentException if the size exceeds - * the byte[] store size multiplied by 8. - */ - public final void forceSize(int size) { - if (size > data.length * 8) { - throw new IllegalArgumentException("Size exceeds byte[] store"); - } - else { - this.size = size; - } - } - - /** - * Returns the number of bytes used to store the - * collection of bits as int. - *

- * - * @return the number of bits in this BitVector. - */ - public final int byteSize() { - return data.length; - } - - /** - * Returns a String representing the - * contents of the bit collection in a way that - * can be printed to a screen or log. - *

- * Note that this representation will ALLWAYS - * show the MSB to the left and the LSB to the right - * in each byte. - * - * @return a String representing this BitVector. - */ - public String toString() { - StringBuilder sbuf = new StringBuilder(); - for (int i = 0; i < data.length; i++) { - - int numberOfBitsToPrint = Byte.SIZE; - int remainingBits = size - (i * Byte.SIZE); - if (remainingBits < Byte.SIZE) { - numberOfBitsToPrint = remainingBits; - } - - sbuf.append(String.format("%" + numberOfBitsToPrint + "s", Integer.toBinaryString(data[i] & 0xFF)).replace(' ', '0')); - sbuf.append(" "); - } - return sbuf.toString(); - } - - /** - * Returns the index of the byte in the the byte array - * that contains the given bit. - *

- * - * @param index the index of the bit. - * - * @return the index of the byte where the given bit is stored. - * - * @throws IndexOutOfBoundsException if index is - * out of bounds. - */ - private int byteIndex(int index) throws IndexOutOfBoundsException { - - if (index < 0 || index >= data.length * 8) { - throw new IndexOutOfBoundsException(); - } - else { - return index / 8; - } - } - - /** - * Returns the index of the given bit in the byte - * where it it stored. - *

- * - * @param index the index of the bit. - * - * @return the bit index relative to the position in the byte - * that stores the specified bit. - * - * @throws IndexOutOfBoundsException if index is - * out of bounds. - */ - private int bitIndex(int index) throws IndexOutOfBoundsException { - - if (index < 0 || index >= data.length * 8) { - throw new IndexOutOfBoundsException(); - } - else { - return index % 8; - } - } - - private int translateIndex(int idx) { - if (MSBAccess) { - int mod4 = idx % 4; - int div4 = idx / 4; - - if ((div4 % 2) != 0) { - //odd - return (idx + ODD_OFFSETS[mod4]); - } - else { - //straight - return (idx + STRAIGHT_OFFSETS[mod4]); - } - } - else { - return idx; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/ModbusUtil.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/ModbusUtil.java deleted file mode 100644 index 66f5466..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/ModbusUtil.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.io.BytesOutputStream; -import com.ghgande.j2mod.modbus.msg.ModbusMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.List; - -/** - * Helper class that provides utility methods. - * - * @author Dieter Wimberger - * @author John Charlton - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public final class ModbusUtil { - - private static final Logger logger = LoggerFactory.getLogger(ModbusUtil.class); - - /* Table of CRC values for high-order byte */ - private final static short[] auchCRCHi = { - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 - }; - /* Table of CRC values for low-order byte */ - private final static short[] auchCRCLo = { - 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, - 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, - 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, - 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, - 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, - 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, - 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, - 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, - 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, - 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, - 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, - 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, - 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, - 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, - 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, - 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, - 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, - 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, - 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, - 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, - 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, - 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, - 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, - 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, - 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, - 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 - }; - - /** - * Converts a ModbusMessage instance into - * a hex encoded string representation. - * - * @param msg the message to be converted. - * - * @return the converted hex encoded string representation of the message. - */ - public static String toHex(ModbusMessage msg) { - BytesOutputStream byteOutputStream = new BytesOutputStream(Modbus.MAX_MESSAGE_LENGTH); - String ret = "-1"; - try { - msg.writeTo(byteOutputStream); - ret = toHex(byteOutputStream.getBuffer(), 0, byteOutputStream.size()); - } - catch (IOException ex) { - logger.debug("Hex conversion error {}", ex); - } - return ret; - } - - /** - * Returns the given byte[] as hex encoded string. - * - * @param data a byte[] array. - * - * @return a hex encoded String. - */ - public static String toHex(byte[] data) { - return toHex(data, 0, data.length); - } - - /** - * Returns a String containing unsigned hexadecimal - * numbers as digits. - * The String will coontain two hex digit characters - * for each byte from the passed in byte[].
- * The bytes will be separated by a space character. - * - * @param data the array of bytes to be converted into a hex-string. - * @param off the offset to start converting from. - * @param end the offset of the end of the byte array. - * - * @return the generated hexadecimal representation as String. - */ - public static String toHex(byte[] data, int off, int end) { - //double size, two bytes (hex range) for one byte - StringBuilder buf = new StringBuilder(data.length * 2); - if (end > data.length) { - end = data.length; - } - for (int i = off; i < end; i++) { - //don't forget the second hex digit - if (((int)data[i] & 0xff) < 0x10) { - buf.append("0"); - } - buf.append(Long.toString((int)data[i] & 0xff, 16).toUpperCase()); - if (i < end - 1) { - buf.append(" "); - } - } - return buf.toString(); - } - - /** - * Returns a byte[] containing the given - * byte as unsigned hexadecimal number digits. - * - * @param i the int to be converted into a hex string. - * - * @return the generated hexadecimal representation as byte[]. - */ - public static byte[] toHex(int i) { - StringBuilder buf = new StringBuilder(2); - //don't forget the second hex digit - if ((i & 0xff) < 0x10) { - buf.append("0"); - } - buf.append(Long.toString(i & 0xff, 16).toUpperCase()); - try { - return buf.toString().getBytes("US-ASCII"); - } - catch (Exception e) { - logger.debug("Problem converting bytes to string - {}", e.getMessage()); - } - return null; - } - - /** - * Converts the register (a 16 bit value) into an unsigned short. - * The value returned is: - * - *

(((a & 0xff) << 8) | (b & 0xff))
- * - * This conversion has been taken from the documentation of - * the DataInput interface. - * - * @param bytes a register as byte[2]. - * - * @return the unsigned short value as int. - * - * @see java.io.DataInput - */ - public static int registerToUnsignedShort(byte[] bytes) { - return ((bytes[0] & 0xff) << 8 | (bytes[1] & 0xff)); - } - - /** - * Converts the given unsigned short into a register - * (2 bytes). - * The byte values in the register, in the order - * shown, are: - * - *

-     * (byte)(0xff & (v >> 8))
-     * (byte)(0xff & v)
-     * 
- * - * This conversion has been taken from the documentation of - * the DataOutput interface. - * - * @param v Value to convert - * - * @return the register as byte[2]. - * - * @see java.io.DataOutput - */ - public static byte[] unsignedShortToRegister(int v) { - byte[] register = new byte[2]; - register[0] = (byte)(0xff & (v >> 8)); - register[1] = (byte)(0xff & v); - return register; - } - - /** - * Converts the given register (16-bit value) into - * a short. - * The value returned is: - * - *

-     * (short)((a << 8) | (b & 0xff))
-     * 
- * - * This conversion has been taken from the documentation of - * the DataInput interface. - * - * @param bytes bytes a register as byte[2]. - * - * @return the signed short as short. - */ - public static short registerToShort(byte[] bytes) { - return (short)((bytes[0] << 8) | (bytes[1] & 0xff)); - } - - /** - * Converts the register (16-bit value) at the given index - * into a short. - * The value returned is: - * - *

-     * (short)((a << 8) | (b & 0xff))
-     * 
- * - * This conversion has been taken from the documentation of - * the DataInput interface. - * - * @param bytes a byte[] containing a short value. - * @param idx an offset into the given byte[]. - * - * @return the signed short as short. - */ - public static short registerToShort(byte[] bytes, int idx) { - return (short)((bytes[idx] << 8) | (bytes[idx + 1] & 0xff)); - } - - /** - * Converts the given short into a register - * (2 bytes). - * The byte values in the register, in the order - * shown, are: - * - *

-     * (byte)(0xff & (v >> 8))
-     * (byte)(0xff & v)
-     * 
- * - * @param s Value to convert - * - * @return a register containing the given short value. - */ - public static byte[] shortToRegister(short s) { - byte[] register = new byte[2]; - register[0] = (byte)(0xff & (s >> 8)); - register[1] = (byte)(0xff & s); - return register; - } - - /** - * Converts a byte[4] binary int value to a primitive int.
- * The value returned is: - * - *

-     * (((a & 0xff) << 24) | ((b & 0xff) << 16) |
-     *  ((c & 0xff) << 8) | (d & 0xff))
-     * 
- * - * @param bytes registers as byte[4]. - * - * @return the integer contained in the given register bytes. - */ - public static int registersToInt(byte[] bytes) { - return (((bytes[0] & 0xff) << 24) | - ((bytes[1] & 0xff) << 16) | - ((bytes[2] & 0xff) << 8) | - (bytes[3] & 0xff) - ); - } - - /** - * Converts an int value to a byte[4] array. - * - * @param v the value to be converted. - * - * @return a byte[4] containing the value. - */ - public static byte[] intToRegisters(int v) { - byte[] registers = new byte[4]; - registers[0] = (byte)(0xff & (v >> 24)); - registers[1] = (byte)(0xff & (v >> 16)); - registers[2] = (byte)(0xff & (v >> 8)); - registers[3] = (byte)(0xff & v); - return registers; - } - - /** - * Converts a byte[8] binary long value into a long - * primitive. - * - * @param bytes a byte[8] containing a long value. - * - * @return a long value. - */ - public static long registersToLong(byte[] bytes) { - return ((((long)(bytes[0] & 0xff) << 56) | - ((long)(bytes[1] & 0xff) << 48) | - ((long)(bytes[2] & 0xff) << 40) | - ((long)(bytes[3] & 0xff) << 32) | - ((long)(bytes[4] & 0xff) << 24) | - ((long)(bytes[5] & 0xff) << 16) | - ((long)(bytes[6] & 0xff) << 8) | - ((long)(bytes[7] & 0xff))) - ); - } - - /** - * Converts a long value to a byte[8]. - * - * @param v the value to be converted. - * - * @return a byte[8] containing the long value. - */ - public static byte[] longToRegisters(long v) { - byte[] registers = new byte[8]; - registers[0] = (byte)(0xff & (v >> 56)); - registers[1] = (byte)(0xff & (v >> 48)); - registers[2] = (byte)(0xff & (v >> 40)); - registers[3] = (byte)(0xff & (v >> 32)); - registers[4] = (byte)(0xff & (v >> 24)); - registers[5] = (byte)(0xff & (v >> 16)); - registers[6] = (byte)(0xff & (v >> 8)); - registers[7] = (byte)(0xff & v); - return registers; - } - - /** - * Converts a byte[4] binary float value to a float primitive. - * - * @param bytes the byte[4] containing the float value. - * - * @return a float value. - */ - public static float registersToFloat(byte[] bytes) { - return Float.intBitsToFloat((((bytes[0] & 0xff) << 24) | - ((bytes[1] & 0xff) << 16) | - ((bytes[2] & 0xff) << 8) | - (bytes[3] & 0xff) - )); - } - - /** - * Converts a float value to a byte[4] binary float value. - * - * @param f the float to be converted. - * - * @return a byte[4] containing the float value. - */ - public static byte[] floatToRegisters(float f) { - return intToRegisters(Float.floatToIntBits(f)); - } - - /** - * Converts a byte[8] binary double value into a double primitive. - * - * @param bytes a byte[8] to be converted. - * - * @return a double value. - */ - public static double registersToDouble(byte[] bytes) { - return Double.longBitsToDouble(((((long)(bytes[0] & 0xff) << 56) | - ((long)(bytes[1] & 0xff) << 48) | - ((long)(bytes[2] & 0xff) << 40) | - ((long)(bytes[3] & 0xff) << 32) | - ((long)(bytes[4] & 0xff) << 24) | - ((long)(bytes[5] & 0xff) << 16) | - ((long)(bytes[6] & 0xff) << 8) | - ((long)(bytes[7] & 0xff))) - )); - } - - /** - * Converts a double value to a byte[8]. - * - * @param d the double to be converted. - * - * @return a byte[8]. - */ - public static byte[] doubleToRegisters(double d) { - return longToRegisters(Double.doubleToLongBits(d)); - } - - /** - * Converts an unsigned byte to an integer. - * - * @param b the byte to be converted. - * - * @return an integer containing the unsigned byte value. - */ - public static int unsignedByteToInt(byte b) { - return (int)b & 0xFF; - } - - /** - * Returns the low byte of an integer word. - * - * @param wd word to get low byte from - * - * @return low byte of word - */ - public static byte lowByte(int wd) { - return Integer.valueOf(0xff & wd).byteValue(); - } - - /** - * @param wd word to get high byte from - * - * @return high byte - */ - public static byte hiByte(int wd) { - return Integer.valueOf(0xff & (wd >> 8)).byteValue(); - } - - /** - * Makes a word from 2 bytes - * - * @param hibyte High byte - * @param lowbyte Low byte - * - * @return Word - */ - public static int makeWord(int hibyte, int lowbyte) { - int hi = 0xFF & hibyte; - int low = 0xFF & lowbyte; - return ((hi << 8) | low); - } - - public static int[] calculateCRC(byte[] data, int offset, int len) { - - int[] crc = {0xFF, 0xFF}; - int nextByte; - int uIndex; /* will index into CRC lookup*/ /* table */ - /* pass through message buffer */ - for (int i = offset; i < len && i < data.length; i++) { - nextByte = 0xFF & ((int)data[i]); - uIndex = crc[0] ^ nextByte; //*puchMsg++; /* calculate the CRC */ - crc[0] = crc[1] ^ auchCRCHi[uIndex]; - crc[1] = auchCRCLo[uIndex]; - } - - return crc; - } - - /** - * Return true if the string is null or empty - * - * @param value String to check - * @return True if the value is blank or empty - */ - public static boolean isBlank(String value) { - return value == null || value.isEmpty(); - } - - /** - * Return true if the list is null or empty - * - * @param list List to check - * @return True if the list is blank or empty - */ - public static boolean isBlank(List list) { - return list == null || list.isEmpty(); - } - - /** - * Return true if the array is null or empty - * - * @param list Array to check - * @return True if the array is blank or empty - */ - public static boolean isBlank(Object[] list) { - return list == null || list.length == 0; - } - - /** - * Sleeps safely for the specified amount of time unless awoken by an interruption - * - * @param time Time in milliseconds - */ - public static void sleep(long time) { - try { - Thread.sleep(time); - } - catch (InterruptedException ex) { - logger.warn("Backout sleep timer has been interrupted"); - } - - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/Observable.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/Observable.java deleted file mode 100644 index a7861ff..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/Observable.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Vector; - -/** - * A cleanroom implementation of the Observable pattern. - * - * @author Dieter Wimberger (wimpi) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class Observable { - - private static final Logger logger = LoggerFactory.getLogger(Observable.class); - - private Vector observers; - - /** - * Constructs a new Observable instance. - */ - public Observable() { - observers = new Vector(10); - } - - public synchronized int getObserverCount() { - return observers.size(); - } - - /** - * Adds an observer instance if it is not already in the set of observers - * for this Observable. - * - * @param o an observer instance to be added. - */ - public synchronized void addObserver(Observer o) { - if (!observers.contains(o)) { - observers.addElement(o); - } - } - - /** - * Removes an observer instance from the set of observers of this - * Observable. - * - * @param o an observer instance to be removed. - */ - public synchronized void removeObserver(Observer o) { - observers.removeElement(o); - } - - /** - * Removes all observer instances from the set of observers of this - * Observable. - */ - public synchronized void removeObservers() { - observers.removeAllElements(); - } - - /** - * Notifies all observer instances in the set of observers of this - * Observable. - * - * @param arg an arbitrary argument to be passed. - */ - public synchronized void notifyObservers(Object arg) { - for (int i = 0; i < observers.size(); i++) { - observers.elementAt(i).update(this, arg); - } - } -} diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/Observer.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/Observer.java deleted file mode 100644 index 46d0466..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/Observer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; - -/** - * A cleanroom implementation of the Observer interface - * for the Observable design pattern. - * - * @author Dieter Wimberger (wimpi) - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public interface Observer { - - /** - * Updates the state of this Observer to be in - * synch with an Observable instance. - * The argument should usually be an indication of the - * aspects that changed in the Observable. - * - * @param o an Observable instance. - * @param arg an arbitrary argument to be passed. - */ - void update(Observable o, Object arg); - -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/SerialParameters.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/SerialParameters.java deleted file mode 100644 index 80c9011..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/SerialParameters.java +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.net.AbstractSerialConnection; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Properties; - -/** - * Helper class wrapping all serial port communication parameters. - * Very similar to the javax.comm demos, however, not the same. - * - * @author Dieter Wimberger - * @author John Charlton - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class SerialParameters { - - private static final Logger logger = LoggerFactory.getLogger(SerialParameters.class); - - //instance attributes - private String portName; - private int baudRate; - private int flowControlIn; - private int flowControlOut; - private int databits; - private int stopbits; - private int parity; - private String encoding; - private boolean echo; - private int openDelay; - - /** - * Constructs a new SerialParameters instance with - * default values. - */ - public SerialParameters() { - portName = ""; - baudRate = 9600; - flowControlIn = AbstractSerialConnection.FLOW_CONTROL_DISABLED; - flowControlOut = AbstractSerialConnection.FLOW_CONTROL_DISABLED; - databits = 8; - stopbits = AbstractSerialConnection.ONE_STOP_BIT; - parity = AbstractSerialConnection.NO_PARITY; - encoding = Modbus.DEFAULT_SERIAL_ENCODING; - echo = false; - openDelay = AbstractSerialConnection.OPEN_DELAY; - } - - /** - * Constructs a new SerialParameters instance with - * given parameters. - * - * @param portName The name of the port. - * @param baudRate The baud rate. - * @param flowControlIn Type of flow control for receiving. - * @param flowControlOut Type of flow control for sending. - * @param databits The number of data bits. - * @param stopbits The number of stop bits. - * @param parity The type of parity. - * @param echo Flag for setting the RS485 echo mode. - */ - public SerialParameters(String portName, int baudRate, - int flowControlIn, - int flowControlOut, - int databits, - int stopbits, - int parity, - boolean echo) { - this.portName = portName; - this.baudRate = baudRate; - this.flowControlIn = flowControlIn; - this.flowControlOut = flowControlOut; - this.databits = databits; - this.stopbits = stopbits; - this.parity = parity; - this.echo = echo; - } - - /** - * Constructs a new SerialParameters instance with - * parameters obtained from a Properties instance. - * - * @param props a Properties instance. - * @param prefix a prefix for the properties keys if embedded into - * other properties. - */ - public SerialParameters(Properties props, String prefix) { - if (prefix == null) { - prefix = ""; - } - setPortName(props.getProperty(prefix + "portName", "")); - setBaudRate(props.getProperty(prefix + "baudRate", "" + 9600)); - setFlowControlIn(props.getProperty(prefix + "flowControlIn", "" + AbstractSerialConnection.FLOW_CONTROL_DISABLED)); - setFlowControlOut(props.getProperty(prefix + "flowControlOut", "" + AbstractSerialConnection.FLOW_CONTROL_DISABLED)); - setParity(props.getProperty(prefix + "parity", "" + AbstractSerialConnection.NO_PARITY)); - setDatabits(props.getProperty(prefix + "databits", "8")); - setStopbits(props.getProperty(prefix + "stopbits", "" + AbstractSerialConnection.ONE_STOP_BIT)); - setEncoding(props.getProperty(prefix + "encoding", Modbus.DEFAULT_SERIAL_ENCODING)); - setEcho("true".equals(props.getProperty(prefix + "echo"))); - setOpenDelay(props.getProperty(prefix + "openDelay", "" + AbstractSerialConnection.OPEN_DELAY)); - } - - /** - * Returns the port name. - * - * @return the port name. - */ - public String getPortName() { - return portName; - } - - /** - * Sets the port name. - * - * @param name the new port name. - */ - public void setPortName(String name) { - portName = name; - } - - /** - * Sets the baud rate. - * - * @param rate the new baud rate. - */ - public void setBaudRate(int rate) { - baudRate = rate; - } - - /** - * Return the baud rate as int. - * - * @return the baud rate as int. - */ - public int getBaudRate() { - return baudRate; - } - - /** - * Sets the baud rate. - * - * @param rate the new baud rate. - */ - public void setBaudRate(String rate) { - baudRate = Integer.parseInt(rate); - } - - /** - * Returns the baud rate as a String. - * - * @return the baud rate as String. - */ - public String getBaudRateString() { - return Integer.toString(baudRate); - } - - /** - * Sets the type of flow control for the input - * as given by the passed in int. - * - * @param flowcontrol the new flow control type. - */ - public void setFlowControlIn(int flowcontrol) { - flowControlIn = flowcontrol; - } - - /** - * Returns the input flow control type as int. - * - * @return the input flow control type as int. - */ - public int getFlowControlIn() { - return flowControlIn; - } - - /** - * Sets the type of flow control for the input - * as given by the passed in String. - * - * @param flowcontrol the flow control for reading type. - */ - public void setFlowControlIn(String flowcontrol) { - flowControlIn = stringToFlow(flowcontrol); - } - - /** - * Returns the input flow control type as String. - * - * @return the input flow control type as String. - */ - public String getFlowControlInString() { - return flowToString(flowControlIn); - } - - /** - * Sets the output flow control type as given - * by the passed in int. - * - * @param flowControlOut new output flow control type as int. - */ - public void setFlowControlOut(int flowControlOut) { - this.flowControlOut = flowControlOut; - } - - /** - * Returns the output flow control type as int. - * - * @return the output flow control type as int. - */ - public int getFlowControlOut() { - return flowControlOut; - } - - /** - * Sets the output flow control type as given - * by the passed in String. - * - * @param flowControlOut the new output flow control type as String. - */ - public void setFlowControlOut(String flowControlOut) { - this.flowControlOut = stringToFlow(flowControlOut); - } - - /** - * Returns the output flow control type as String. - * - * @return the output flow control type as String. - */ - public String getFlowControlOutString() { - return flowToString(flowControlOut); - } - - /** - * Sets the number of data bits. - * - * @param databits the new number of data bits. - */ - public void setDatabits(int databits) { - this.databits = databits; - } - - /** - * Returns the number of data bits as int. - * - * @return the number of data bits as int. - */ - public int getDatabits() { - return databits; - } - - /** - * Sets the number of data bits from the given String. - * - * @param databits the new number of data bits as String. - */ - public void setDatabits(String databits) { - if (!ModbusUtil.isBlank(databits) && databits.matches("[0-9]+")) { - this.databits = Integer.parseInt(databits); - } - else { - this.databits = 8; - } - } - - /** - * Returns the number of data bits as String. - * - * @return the number of data bits as String. - */ - public String getDatabitsString() { - return databits + ""; - } - - /** - * Sets the number of stop bits. - * - * @param stopbits the new number of stop bits setting. - */ - public void setStopbits(int stopbits) { - this.stopbits = stopbits; - } - - /** - * Returns the number of stop bits as int. - * - * @return the number of stop bits as int. - */ - public int getStopbits() { - return stopbits; - } - - /** - * Sets the number of stop bits from the given String. - * - * @param stopbits the number of stop bits as String. - */ - public void setStopbits(String stopbits) { - if (ModbusUtil.isBlank(stopbits) || stopbits.equals("1")) { - this.stopbits = AbstractSerialConnection.ONE_STOP_BIT; - } - else if (stopbits.equals("1.5")) { - this.stopbits = AbstractSerialConnection.ONE_POINT_FIVE_STOP_BITS; - } - else if (stopbits.equals("2")) { - this.stopbits = AbstractSerialConnection.TWO_STOP_BITS; - } - } - - /** - * Returns the number of stop bits as String. - * - * @return the number of stop bits as String. - */ - public String getStopbitsString() { - switch (stopbits) { - case AbstractSerialConnection.ONE_STOP_BIT: - return "1"; - case AbstractSerialConnection.ONE_POINT_FIVE_STOP_BITS: - return "1.5"; - case AbstractSerialConnection.TWO_STOP_BITS: - return "2"; - default: - return "1"; - } - } - - /** - * Sets the parity schema. - * - * @param parity the new parity schema as int. - */ - public void setParity(int parity) { - this.parity = parity; - } - - /** - * Returns the parity schema as int. - * - * @return the parity schema as int. - */ - public int getParity() { - return parity; - } - - /** - * Sets the parity schema from the given - * String. - * - * @param parity the new parity schema as String. - */ - public void setParity(String parity) { - if (ModbusUtil.isBlank(parity) || parity.equalsIgnoreCase("none")) { - this.parity = AbstractSerialConnection.NO_PARITY; - } - else if (parity.equalsIgnoreCase("even")) { - this.parity = AbstractSerialConnection.EVEN_PARITY; - } - else if (parity.equalsIgnoreCase("odd")) { - this.parity = AbstractSerialConnection.ODD_PARITY; - } - else if (parity.equalsIgnoreCase("mark")) { - this.parity = AbstractSerialConnection.MARK_PARITY; - } - else if (parity.equalsIgnoreCase("space")) { - this.parity = AbstractSerialConnection.SPACE_PARITY; - } - else { - this.parity = AbstractSerialConnection.NO_PARITY; - } - } - - /** - * Returns the parity schema as String. - * - * @return the parity schema as String. - */ - public String getParityString() { - switch (parity) { - case AbstractSerialConnection.NO_PARITY: - return "none"; - case AbstractSerialConnection.EVEN_PARITY: - return "even"; - case AbstractSerialConnection.ODD_PARITY: - return "odd"; - case AbstractSerialConnection.MARK_PARITY: - return "mark"; - case AbstractSerialConnection.SPACE_PARITY: - return "space"; - default: - return "none"; - } - } - - /** - * Returns the encoding to be used. - * - * @return the encoding as string. - * - * @see Modbus#SERIAL_ENCODING_ASCII - * @see Modbus#SERIAL_ENCODING_RTU - */ - public String getEncoding() { - return encoding; - } - - /** - * Sets the encoding to be used. - * - * @param enc the encoding as string. - * @see Modbus#SERIAL_ENCODING_ASCII - * @see Modbus#SERIAL_ENCODING_RTU - */ - public void setEncoding(String enc) { - if (!ModbusUtil.isBlank(enc) && - (enc.equalsIgnoreCase(Modbus.SERIAL_ENCODING_ASCII) || enc.equalsIgnoreCase(Modbus.SERIAL_ENCODING_RTU))) { - encoding = enc; - } - else { - encoding = Modbus.DEFAULT_SERIAL_ENCODING; - } - } - - /** - * Get the Echo value. - * - * @return the Echo value. - */ - public boolean isEcho() { - return echo; - } - - /** - * Set the Echo value. - * - * @param newEcho The new Echo value. - */ - public void setEcho(boolean newEcho) { - echo = newEcho; - } - - /** - * Converts a String describing a flow control type to the - * int which is defined in SerialPort. - * - * @param flowcontrol the String describing the flow control type. - * @return the int describing the flow control type. - */ - private int stringToFlow(String flowcontrol) { - if (ModbusUtil.isBlank(flowcontrol) || flowcontrol.equalsIgnoreCase("none")) { - return AbstractSerialConnection.FLOW_CONTROL_DISABLED; - } - else if (flowcontrol.equalsIgnoreCase("xon/xoff out")) { - return AbstractSerialConnection.FLOW_CONTROL_XONXOFF_OUT_ENABLED; - } - else if (flowcontrol.equalsIgnoreCase("xon/xoff in")) { - return AbstractSerialConnection.FLOW_CONTROL_XONXOFF_IN_ENABLED; - } - else if (flowcontrol.equalsIgnoreCase("rts/cts")) { - return AbstractSerialConnection.FLOW_CONTROL_CTS_ENABLED | AbstractSerialConnection.FLOW_CONTROL_RTS_ENABLED; - } - else if (flowcontrol.equalsIgnoreCase("dsr/dtr")) { - return AbstractSerialConnection.FLOW_CONTROL_DSR_ENABLED | AbstractSerialConnection.FLOW_CONTROL_DTR_ENABLED; - } - return AbstractSerialConnection.FLOW_CONTROL_DISABLED; - } - - /** - * Converts an int describing a flow control type to a - * String describing a flow control type. - * - * @param flowcontrol the int describing the - * flow control type. - * @return the String describing the flow control type. - */ - private String flowToString(int flowcontrol) { - switch (flowcontrol) { - case AbstractSerialConnection.FLOW_CONTROL_DISABLED: - return "none"; - case AbstractSerialConnection.FLOW_CONTROL_XONXOFF_OUT_ENABLED: - return "xon/xoff out"; - case AbstractSerialConnection.FLOW_CONTROL_XONXOFF_IN_ENABLED: - return "xon/xoff in"; - case AbstractSerialConnection.FLOW_CONTROL_CTS_ENABLED: - return "rts/cts"; - case AbstractSerialConnection.FLOW_CONTROL_DTR_ENABLED: - return "dsr/dtr"; - default: - return "none"; - } - } - - /** - * Gets the open delay used to prevent some OS from losing the comms port - * - * @return Sleep before an open is attempted on a comms port - */ - public int getOpenDelay() { - return openDelay; - } - - /** - * Sets the sleep time tat occurs just prior to opening a coms port - * Some OS don't like to have their comms ports opened/closed in very quick succession - * particularly, virtual ports. This delay is a rather crude way of stopping the problem that - * a comms port doesn't re-appear immediately after a close - * - * @param openDelay Sleep time in millieseconds - */ - public void setOpenDelay(int openDelay) { - this.openDelay = openDelay; - } - - /** - * Sets the sleep time tat occurs just prior to opening a coms port - * Some OS don't like to have their comms ports opened/closed in very quick succession - * particularly, virtual ports. This delay is a rather crude way of stopping the problem that - * a comms port doesn't re-appear immediately after a close - * - * @param openDelay Sleep time in millieseconds - */ - public void setOpenDelay(String openDelay) { - this.openDelay = Integer.parseInt(openDelay); - } - - @Override - public String toString() { - return "SerialParameters{" + - "portName='" + portName + '\'' + - ", baudRate=" + baudRate + - ", flowControlIn=" + flowControlIn + - ", flowControlOut=" + flowControlOut + - ", databits=" + databits + - ", stopbits=" + stopbits + - ", parity=" + parity + - ", encoding='" + encoding + '\'' + - ", echo=" + echo + - ", openDelay=" + openDelay + - '}'; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ghgande/j2mod/modbus/util/ThreadPool.java b/app/src/main/java/com/ghgande/j2mod/modbus/util/ThreadPool.java deleted file mode 100644 index 11055a0..0000000 --- a/app/src/main/java/com/ghgande/j2mod/modbus/util/ThreadPool.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2002-2016 jamod & j2mod development teams - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ghgande.j2mod.modbus.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Class implementing a simple thread pool. - * - * @author Dieter Wimberger - * @author Steve O'Hara (4NG) - * @version 2.0 (March 2016) - */ -public class ThreadPool { - - private static final Logger logger = LoggerFactory.getLogger(ThreadPool.class); - - private LinkedBlockingQueue taskPool; - private List threadPool = new ArrayList(); - private int size = 1; - private boolean running; - - /** - * Constructs a new ThreadPool instance. - * - * @param size the size of the thread pool. - */ - public ThreadPool(int size) { - this.size = size; - taskPool = new LinkedBlockingQueue(); - initPool(); - } - - /** - * Execute the Runnable instance - * through a thread in this ThreadPool. - * - * @param task the Runnable to be executed. - */ - public synchronized void execute(Runnable task) { - if (running) { - try { - taskPool.put(task); - } - catch (InterruptedException ex) { - //FIXME: Handle!? - } - } - } - - /** - * Initializes the pool, populating it with - * n started threads. - */ - protected void initPool() { - running = true; - for (int i = size; --i >= 0; ) { - PoolThread thread = new PoolThread(); - threadPool.add(thread); - thread.start(); - } - } - - /** - * Shutdown the pool of threads - */ - public void close() { - if (running) { - taskPool.clear(); - running = false; - for (PoolThread thread : threadPool) { - thread.interrupt(); - } - } - } - - /** - * Inner class implementing a thread that can be - * run in a ThreadPool. - * - * @author Dieter Wimberger - * @version 1.2rc1 (09/11/2004) - */ - private class PoolThread extends Thread { - - /** - * Runs the PoolThread. - *

- * This method will infinitely loop, picking - * up available tasks from the LinkedQueue. - */ - public void run() { - logger.debug("Running PoolThread"); - do { - try { - logger.debug(this.toString()); - taskPool.take().run(); - } - catch (Exception ex) { - if (running) { - logger.error("Problem starting receiver thread", ex); - } - } - } while (running); - } - } - -} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/con1.xml b/app/src/main/res/drawable/con1.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ls1.xml b/app/src/main/res/drawable/ls1.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/zyl1.xml b/app/src/main/res/drawable/zyl1.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/zyl2.xml b/app/src/main/res/drawable/zyl2.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_display_message.xml b/app/src/main/res/layout/activity_display_message.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_manual_drive.xml b/app/src/main/res/layout/activity_manual_drive.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_measurement.xml b/app/src/main/res/layout/activity_measurement.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml old mode 100644 new mode 100755 diff --git a/app/src/test/java/com/example/user/myapp/ExampleUnitTest.java b/app/src/test/java/com/example/user/myapp/ExampleUnitTest.java deleted file mode 100644 index 5d89d0d..0000000 --- a/app/src/test/java/com/example/user/myapp/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.user.myapp; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/build.gradle b/build.gradle old mode 100644 new mode 100755 diff --git a/documentation/Tag Liste.xlsx b/documentation/Tag Liste.xlsx old mode 100644 new mode 100755 diff --git a/documentation/doku.ods b/documentation/doku.ods old mode 100644 new mode 100755 diff --git a/gradle.properties b/gradle.properties old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 diff --git a/plc-program/Schauanlage-Elektropneumatik.mnp b/plc-program/Schauanlage-Elektropneumatik.mnp deleted file mode 100644 index 5228ea92d78d71e0db619d7ce8a550d10975a887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35732 zcmV)_K!3kbO9KQH00;;O0FQFfOaK4?000000000003`qb05LT(IWjgiH!?6VGch7e!J4_&c1o`X6ChdGjsF%$hWNmAr!!u3twS;J(WqL{W=#nWnz)x zNFvh|3OA*~>Cm>OXl!sK9mzB;iYEs)FCmF9kG*B)y8cu5ccaoEYV4O@^hMIKP&{^A zB-|OwhSo&VnOHKh9@R$4$IC~C`y=UKW=$*;>yJl*s5}}R4h=?@MPh?P+18epAS$Cz z*2cowA^c!Hs*m=B(xKr2i7pfGWvMOZJOnqdPnK9hrXlE>wiifr@N{(hxjf8e@WFQ+# z4902UQYK6@DBRbDDxyo%$&nOADAOHEWl=f(ek2=4i1rC_?=<_+XbQS2?xGb?WD^wGM2r06r6+DUY2j@y5Ap<2cN+NOcUq^Bzk==lbg(LvaqUsH_4slG(<`w;$Fvx|ZEcp3G(qe`t z$j~HYIRB|5e^8N`5qBd*@)lvdW*H5go^%Xj0v(%HQGoAqqoN@0$Iz9I459-1Pn-B? zo%m=Sel#tmfT2mI4agU5PY>X>@od--+<*af#S)PWbcsrMw_^X*R!WA8yY$8BhrC>Th8xrr2T8O(8^3uizuo%ZeOSk{b-Y39Z_1t8^HNYE@4*riMC zj8&v-;PKeR#^b}cZ}K%fzA5WQUfhmDgtG-Py9I_8M6OYMZ6}>(Z+uO{*BX5FWzqCz z4Zc7qnQ0CtQX|>mKr+!Z7>nZUg+l+S68?HpDLlGe!4yVmrcpm!F_HyH(E(b&hd*vU z;j3w}Q8EgrCi$1z!!V8ZH46yBLm5FD2pFt(NxVo2ymoaL>Mdq$v`9)bVqj=<_|qd%ofN14*<{a z%ZAcf=_`1?m!j|DPEyADEdl1buKtvY^X81;IxN9MKNL?5g>aw6ykZ2)SvRngDU#?J zfKRC0?8D49vTy?)yy?Myk{y`K65u-|1qDx|?DT7V;ciMWEf)H%djwKt_&+a)6sgnQ zkDQgB`_13%OFEBi+$8bUPr%H;|BXN@m7?N77?mx24}}iXL^@2M-fM@qcnu2}oLFW>rv zh?4SXUu<|JPP+1{?J11io-vkFmxB;sGL_4KgYa2_gY2t|sn}wq@T1@2`wrKH9OujS7RPp!M}RwJ}g}I%AeaKwSg%XDWNsGI5lWubk3G{60!p|10 zPKEIpYn4F81u3Fb)L`;i?&9#QQz7S&2x|3l%MA9u1K)1fYDI7_~ zlc8`=W}B#o>+>x@v+al*w_km+E3uQH*#K`_?Q=kY)Oy(C!@&#d_PNFaq}>f6ag^I# zq=SK7DZjGxTWtOH;j5Q_UG*LOr<|x!*fu2G&8iBp@R&$xVc2)hbkS;b0fCz_Cu!9M zLd25>hkI-|{oIG|{pJ*+uoP2)hc&;fk+yQ6ZYiQ^u2E?mC;t#AA->_)}wQBC_u zHrX8sWk#rd-HWZBNGF!M?THY;9LW%k29yn|ZINUrmQuk4hLxb%golOE?$D_8e=H&V zUmWejXeQH3L$O3B7D_a=A{xy^urY<-Zi{6HhH$?oC9fL7>he%B9yU|hX6ceZqt>;D z9n=5F7gN7)I9dcB6jgb!y`WnF1N+vc_ndXZy?ftE`sN-f@v%wggaQt7A+ckN{~R_I zaldc;6RCcOJ$%MVqP`6ux&c;8#z@oQBwt(2k537--Q8iPmw<33#ORG=k|XJXh+vZl z7Tuce?ocX)!D6Mr#G+$agNbO8I`7D1GK>VMRnbmtE8#pn>0}D42r;nbXXyi0wIYC{{@%U&&fCc_xr!! z|NZ{&_kTZ&zZCq4lv#(UliCWqbO6eORx3Az& z4?bLX?C(6ty#y73H)BZ%$_b*vtY|8ZroM3)t@buC2m*~FPR~Y6&n}V^M4n|n%hE$E zw2YBIhI+c`6dZLFpK;FZJO6rupIDfUN!bf+`>G;JKbAR0_cd_Ou8{e)0lPU!a$v56 z2g|VeFw4M&p>ptk>*Kc2qE&y}&O8{nzRf0+ElMD(79I1%+fV*&8F5{dMmrf;j6F$KO^r6b=@}%gvj)XffWPO`o zd-9_y+LMlKjU`7ivbjqGgH+4=U9E;8O!&aP$tC#$NRY>7Y3#!6nj5!kE6G2L&As?( zkFn4%J0mzBo%GqhrSfk*``ojhG*L-3m?4fKn12EDbam$vA?{{3MeRny(Pr_jy2~x1 zT@LQUNVI8_(ku}qN6l&k|DT`^R8rNZJrSniN(ne|+@`brSW9kF_BJP38)O zE{DW+p3+`{(k_XDa64I|^}h{h4fm}AbdLsfz8x9#GgK{E4bGOvwXt-hF_;*N^~c2C zJ&T(uG;7(eZN?hr?Jq%)kUgClk7Q(ED0B*@Hrg8*PG%z%v)^tm+D$)c5EvE--7`Ptv(dtAj8|=iD&89=Rvd}WY9svr| zP&oVmE8$H!rbH;dDicakgoVdKX^Q9O!6&R4TyH*l^sE_E|L8`3G5)K^aKZz~+8zgN zaCKM3hM{GAQOFRKcQtQZqoeOPl;avRdE0;YZlkkFE^Pm^q2BGn=BI~9d(&uJlw6yj)%D09>AsC?j0#Q$}B z&6Tf5XgG3=d#9(yP1T1jSzf>X{^`Rv-+$se1aPD5g}zw4AL;bU-^r({^_2wp=SgT% zbuPn3cj+{`C<^ClHu_EhpMaKhf&cF2d(#`L-X!vPczd5--QN&Lq{<6pcSOFHQuY-? zO1^A|k~-R*oTk=vJLTZ_Y7Bm@vHH1+x~^6$;~t)UY7yWZr;J1cmby=+(R34iXIX4; zhz87Exv%%cN4ol{ku)Sewqyc$0g48Xaut}`0B){>xK!=HHCzECzA$e&SEa+2(-^#R zSmNMq(;&2&V!1X3F1lW3&oWiVWaS$kz?0ebDtn z_uC~TuxhW2?2V2utWMGfU0#@>MCAX3H#K9CB8l!;JRa+d3?vib%(>gb58QFj*_Y9vaebVH>^#mH`p_QE19~{?N3270 zLVROvOIs)E(@|BVUpeVXNTFdXi_)^^IlCX%(N*P zB^?Y24D~?7nJw^W3TGhc%!s;`Gokz|WJPnHWavWIFnI`iN9w!KUF+bsUR|)-%#wXW zo?I=IIvE~qQ0VLMETsMrZv7J7tvXsH^sGQLv$pI(n`;G{8G-wq5Lh&b3bhEVbjQoJ$HR9&u|+Tdyd4Zk*NJQd0Yhov8OlgF+9Xbt-gSyQ za_x>i7Q0b-5LHI|Na%DI@qjLghX&W9vRI~PTevfV#eQ--IDvf`s`mx9VpbQ9Ww&>s zz`#%}9!^IRY-^vXFpG1CwBCqorF! zpJ|p&886&`N+3Ex{2WMd3b>rbYRaYwrWs5d%hzxf435OY-Glgxy*0jAieCy09_IlK zB^JhYj74M2e;r84>xXlsBcb@RwKB(dF@^-o&U-@HA*zi4;(G|aNn;kzM_3TtPSEM- zVpnu&bwzk~rrG#9E0^)Lz+ikS%DF(zA6iKVw&pN$oo^YeeV36DG&3e<b(48IN@_^MHyv zT5%BY>Djg=%`b?gc}S8pkUZVA8~x0VOB+7;sdm-wQ&laOfvy29F9ZEPC*8=DiT^>@ z)h|R`L8ce17cFYPF|q$jF?w9NuNY1-xLz}FR+2+G2V!ifDWVRgh3e9-Ar_oEFNkF! z*^eNdQorE@(w{7h45@1H#Yo}@u;|#mzxbC*lbsd8K;jY8_e{5l$ zMI}sSrd?jihh#;-vo8&&5dDyNQ;VzebBM10sIa#(hv@nb+tvvwe*7F_fcsKo4$<|M ztvN*3nRey&gG7IBRFhCz#uK1n;A7Wk``RgOC5?)`sMDbStk|HZlxGf?=ep zrlZwB)q>et=oh5P7M!0p?7L;guN+o$8s(2f1p&cgL1$nS>P zI3K}*7!TLN4L)`C!|ehhqlnqDE{hIZGQXpvrE@{Yg3gYPc?T|9ylC#6xt;Uc+7`^~ zSkyXyZhL2EOY6LrmR9&@!Q9r?`3u?)m^**L;xC;dUI{<PtpzEF@672;@m8t!T(BF8gOdx}cw5(?swxFw(nWufpG&VxX zMs(0+WP$vv(vb*$Uh?2)ht8h1>1_`Q^1)Ut__0V}b)5`M2YZg;qzI)wY&#*cZCh6| zF}U#Tx6Xg^ynSB9xEwBQZ8R$GCPy;S5U0~`zIgZI9j~3uLflz9PDS9O{y}TKn38;Q zkUG2g<991sxp!{q-M?P=-o>L?-5@HSzDdSL!SD?q0a{Suc}(!&&Y#;n6C-SQuIE_397dwn3xk zIWd)Wp*b?Vb)n^Gc+240C9r6C`?UzHG`wj!2?>8)!&`tZ_wOp9>rf{nLC>py*PRAN z;@&EaZ=$SyTfmUW_%nD6eWYK*ZA6E9a(h!%KX`V6S)-kpOQW?KG@7EEQ`Mc0e4Vz& zP~4|j2J1)|=|aoVmmq`dl=aNAPUK59h^&oK!Vn|Kak)+7!+nWmoO0k@8qo5>yDrUT z7oDZZ`Q7wdKFAA16>1J zUIzLtPP&mP6MxKt)6o66t)g84&TZ(`b{o2XXW%6TSGoIH^QI*^QsNgf*C9Omo0vkf z9|3IQ+;jidt~bm5lvF(HyBdIhZ5wbeS1)ax!R~P1XxHwr4*H^9hxJK$bMC2V4$uB( z=-l&JTOZ(lPldb{-=6zD(YNP8il0s2p8M~%e0%N_?26YrmA*a7an!w7?%RVLC3`Ey5x*%Q6*Xy@q?&@-13OCq-+6_}E?o$b8CAjtG!_~D#a7vMO=z|+U;zS}r zIhU3Dak%}PyxxP{_Y(a?TV(#4G4k`cd)57g_w%^Pz&_ok#2wa_kuozY4-!`cnteZy z`+N2{*QQ;jn5JV#37ob&e(x4eeG$1?|RYjvn6Hx*R% zgJ;K>HQL5p8f}_EqbbUXsykgPp^7!3qsc+Ld($%l)-h%dZt<@@^%d(Yh%=7 zh!NyC-ljt88MTa44!lbPT3&e9_FRTRk#*j6o`k%cYdjXM2H`oR|m#dft(t-uzF&TGi z3&c9;kzI#%f8IPkDw@Ny#|%9_q;I~j#s7GhkLO7h_Euazo+mAC31RB;@jPzJ<>NWV zu7tfr>GGjWN8OFBx_mrGS#kMzZX0u#j|bLtdSEY1&mnM&66QKes+@0^k7pj-R>N&0 z+;(s-AJ5Hjduf8Wd^~g2{e^e=c)(-f8L}yKS7?h#nWdEnp{oJSzRSmRqCM8twM!T- z5fcaI)#anb8NH-MoAc=MVf%PMo)2xZbt`~@GG@lHW*<>(5lJ@0Q*IFnB+-i`A|N0` z1!C_shKN!v7m5{C`Pmx9LL+$V)cC^VdW~+UMvJrOnzV}0hQ6Cd&(nd<++$jF(}up6 z3c9L?s&ziYV}^vCHAC5fA#P8XjupYhhkyOV&&hrh`^8o7b&jB&6m5^gQ9l@=tr6w! zEb|qc2Da)49&-qBhxF-hN!=S7?u`t~x0Vq|MGu2A-&%%S0ay)`s4sg09+q2L5j`+^$>LtW&l{?Thh_mkUW{I2f=Nj3OZ$GChS*}ndw4QF$eEKb~JvavadG= ztnNmnzxBB=lC^gtnwC_&)gRIG6~th4Cw>msL5LAaEPy;em_C7xTlP9e=wYr!6}o-Aa;vHj&zSqwg|&Mg zK$bU@rsV5d3=bCNR=|Kb)8C0ryI^S#ef^Ump@zyGc2&KQypR?U>2FBHp`7^ei$6sl z@_)yTs@9{z=;ClpI8eBZ{l6rcUegWx`*%e`VJyPeN76~MBW_nDF_;|+Cf0Prj;`II zQQ-lqkdy+t5@Wr5k2kt4!s<+j98p{?y&zlq(+zejqdg=2@z_8+IUXWLFe(wAtx94; zjBH9JB-eB=!eGePE7HA@Xe3QGi0bUZV3tO*WW2y#w!?pMG^pHRpj3RceN|*s++V>L zm3^e#sZ71X2|spMjHZZYOBjKljWn$8HfB*F+j$9^a0Bkvffb3_r2CVu52483V|46z zzN_n>0jcQfs?!NlJKp~A){{T@jYeOG;x`#?XQl&FMA57p&(`e5E_O1WcUa_mlz22Z z*a}%xB<(?!MebFw1gWHBBn?|-G>Rkz_kni{=jAY$2`#zE1U;qBnoIxy^TcY(F9Osm z&z`mf9$V+xu1~~bY-Ts#hRAygqc3CMv#o4HWZ!*d-mo+6HmoIEpjX=#@QQnqPTFGG z7Pv$K9iA!A{XiUWl4YI|a7t_M_f&}Mm>F{2mz)Z*P)qmyp<4I7Do?tv$P4UfzgJn; zey?ymx^*dOd2D-+k)g?r?eAF~+XF>HoySWbyOoiYb%x8W=wqZN-k2FJk<3f(9kwDm z3H=q4^H$3D^#mrxC98o;{zQ+60&7tN7qRy;<&fn)NZJ8bUcIPucn5Kj-Y3)r8_Ym@ zALqPc2g9Q$`C}TpI0AgGN)7^KW&hYb8{%HU;GU$}(7Iz85`cImTVc;5ubJhgc@EuUv!3+8DiU zh!Mc5v^o9jE3=G~bKa!|Eg!s#!gV?f4zkRUI zme?1R`jKfj+Ru)E6+W1%UA1Yds^u`ywV>r=pi{VZyO9|a_qAIHu<|XkRkUE+hyhk) z3;(!A(LsahOt4FQhnu%8$&nJjuoz(FJKP|^ifDws#TNQ7SH5qFR6gsyd@lf*f7@*Qg{z{>lHT?so&>0hI=T-}YW23UDNvJznBTRi3gRz5i3)B85uo`c)J33DAK zRnB*SmG=p_y$iQbp_u)-04pEZnm)1v&jbjt@@g!bR#?yP!0o^Ggs%55+WN4}(#nH& ztpUyc%%-o}9_xBzmoQvnx;$-*;hF_lX>!Kz!i&o-m6M~BUd!8hQqG>dORReGqNMg) z#?6!GBi0sguwQI#W_63qlL!AV)g$N9e0cMGS8qYwERG>wSxvn1=GRjp!`j(M?p>7o zl#+VpfrvZ{-PLFoT00QylEw2%{_^vcUUJF~JB?^&Tr;!v^A24?hxg7A!VJ$D%K5#2nSuuQYA$g<`l<9lM zBq-DOJHsmL6f2tlEgHpYM@;%&RP|dbN~$dy$1hk0>qt)PLd(%Omcg}4WYG)OY@Ntz z53W{NDv-V2tf%|lx2vQ7-7-#&ykNS}a`b}9;M!;*xSg!Vg_xuNv8#Ada8@kczuL8Q zt%Lr3-Yi|;Q;H(+Gk=ki?!rPh(bgra#|&-VErJO2m#AuB#oG0kq>#?f$l4{PD(zi= zv3k{<@o0L+=4e7^D#btTr%KXVw|IR|S+RIgcI+))Vt_&*ws$weEXmj+n!^csw|Mu0 zTLl#JJ1F1`&f+Bm@lTov7H<~q-*M1Ut20=QIw~1TWj2S8>WpMIXOpR;5|Qk-WP0;# za)@=NDLx!B>wVrm?CPDCRy;VG*42gPTqtNkvndn+$`k{BX-M747OAVRcxbIwajwQ_ zL37}4_=l{-cyFN((z$-J+@m3qld1+PIfi5!%qz?qjvuC_tC5 zW>P{|^+pPPPzBw1HIvXnY!S^K7M7v-VFt%PtSU)w843%WtAv*pPKWkqEyHGEbFlk_ z=8_RVJ%CFdHs?Q{lh@=oHcLkQ#~TFA@g7$HR&@(=y~3l_E8yA5W~1p8b=hkDTW>V& zsW+O=)b5dIsoK(XG)=cYnl!es&=^f@R2zvFztv4Tq%2m@(W|UT&jYMiRwD`$q=A2( z1L36$Q4e3a_roGHQlDkU*)f{qSu|0|k~Is**Z6Nz6=KOixk)ro3XtMwb2`p{gRSW} zzpZ2E_>!&xCBc6^D~oq(kwe-voLc@E-191lBhjt59{{8DOqMn-GC4dp3iu-U)sbq$98TU|nuBA+%#pX5*< zQ?|t*GQ$6~$zH?$2WLpGUYp-1-TtBmIFGovZR~>G}uZwwmxfxShgTy8Z{@ z_Opp#>5|%;j)|*sv9WXoiz6FL7n*$=%m3Y!2+*F*>A!53ColdNGpB1Xqb*{Hy?0GWku;5T+&Mw8BQi z4rwb(=G^+i%B?$5t#(~#+snJdOQpRG*tTf2 zU_sk1Xu*QEUDbjG&)8}~DZ5?^9>}+#hN46%WJ@>m?kg1ApwSc_$$Q@L9THjJ0MrC@{QHHrmm z91Asl8nzkIuvnLdgK8Sa#*KzC>og4S0vg&^3-n>xR|*Pxb$9$Sq{IrlDx;E{t4Dht zxOw-k;^z5|lPfqw-4aJQUGb_x%e<_3EdXbW%@wZ{m%K&BF%(#f8gjf07vTqv8@+F3~RhkKC2j^=d((4jlE|Lo0ZVmz=|CU_EHgrh)aKnPxZR*ZCxG>+Eenl-vk;VBaHlQb zmtjyg>G$6j$|62M4JU2^*|hmKlYZ^e>({?GBm47C`n9NL?yc3YwY$xqwdsj&w$N1Y z{Y#d?I-AnhgO+P#q6F7w-@ZntZ@+7+16u9d1oVqG9UJ<=X$8+JihyUIYAVIzybqbj zwJ`5f@P!I{EAu`DUx@QQex&%>ocAgC%+|b5!S8JfUvv>Cd|4+_lGOS4UwYe7E7^OIJjr z#C~p^zN%{m!E-C2y$)M5TkJ;hvSQK$26w^jZVgjD0AnVwkz<^uT7^I6SSz!* zn_9IJ&<6RgupHj3HMbf#8?smlZ`M=?O@f*O=jxk-0frpL~)i za66|2kl)x$5(RFzJV_Mzv10+EOGQ_&Rfex{W^2K+xRLz+`Wwj$y+?Z|`F)eh*Y>uO zC!FiXU8N5C{wx+{GkX@5@xuxUeex0316a@f(JqUuP;|9xojVP#B2I(rBq74NX$!V! zyJ-X063(w?V=5PliuJ*>7tBP4y|v8>k#V4Pe*UV|#GET(hc&?*c*QbUN2-Y~v>e^E zGPrh$EDFsT)`_gOFPJt)mznl-yPG@(KD3OJBV}3_T8@)MGPq8M!EOdEGzzV$0>^3 z6Zi;jm%;4{xV=ia>L{slzUOWNunAb;e7LY@)4QTe=sDbYr@IOQ9em564s;_*j;3j`mFyF|EPiwnKQpRsMCqnio4yPZQ&YhIsUSC4LjY_HhUa|<3cURhp&gS~so8u)+r*ixpcJGQ-x*t_R`mnOk7fYG5gM0&}^Au4u#~si`VAjVAN2L2;?Yb8XVlTwp zxnU;AL%KOR!Qpdw_8yc7d+WF$crpM2u@Js33_|iocmcD8uGioO+qby>1MtXENF;z~ z1KheHGc0rS9}l;u;RZ%w0UV>}Cqffc+XC24q5x)c3&7??WM{WW;PwXO8zzkfkUt`$ z9G*c~SKxUl_jEw~D8TtR_~P7@?r+p^hNUwd+7?R;_N0@kNIDyfWOlEtcyq;)&fDB* zauDqsR=(DpVF{wDsCXbOwtw3;Ces_|!ZE2`p-h&Yv5DW1V@>Iis)LctvSd1TTr!aj z#e=AfK3W5%420rvWNY70a$9?Ld1Tv?7(H9HFB?i{`v%gHNCM74#dvk0DN#B6C9%;+ zm=u!fCV>OU--T+qEN~>N>}5%`VBpZu2!;^(wD1dWB1~x~+ z@I^IACx8cbv`h2x}j+4--9QCJhR zEtw88ym2cNuu>-SY*S<)D|=QJ61`C=`!` zn?ggwAyU8wJQg>cF*Y`-Wr3)Lr7biuXV zQ=_(o=mMyhSG@Q6;UBJRb)!HKmGqCq;$b%2ONK+6l4)5omXIa&YF6&PJ zDiz1$9r`AWa;}?oBooot;7FRh&7%Eu>&|6d2%}9XvOOG5CZrAuKe4Al-^a* z2h47r+lc>}GdGKhyH+e+fg2{8OlL8Prsc2?%IbmG6VSoR11{KlL-*W4Ar$+fXWIJqsO zU+_nN=v$cQg1rY>D)^;?Nbf0vW%Naj1{q&{_6lnm-*kV=QpS&?2Rv*o<2x@$@=P3m zJd6BmlOvcP>X-XTc*fZTLD-X5b%|GJbl-&2FhCE_F=~nB6jOcI$%1*0$L# z^Q|@WQd|?dp|3%?KNu!MzX&$sD>~RHV=8Se<2C>K$YRF-{@z-~>yDjaF=M#JTE-ut z+bm}E?PD$D^;LUX%vk%P#f($lw3u;^udQXg;oXxhX8dQJwTw6YJZv%JFJG~i@yFZS zEM`1DYc1o>SNp7Gyu;ONHRAH5)r|44`PdTRSetJY4HQF`LXE&20u27N74~6Qo;KPCJ^8_Zv!@G`>>%k zfGsTnE~!b?sOSrVADDAR!~sR8&(|Tr%LNy%=4@RvZ#mtfp3~q3pe{G^fx)skI}}ML zB3Ya#f$_i@2nGRA@0ViRZEZ;O11NCsLPgPF54K1!jWSzAqpxqI9|P+SWj1f2Mge)H zwO%HTX6oXtMrwBae>NTc?(}{)stTgA0rnicAK+|hkH@w~B*GU&JK`~HsRWTH8thz; zs-nS6XL6)J9_fsw>6i3jA8t9>L-5M_xxSQtV zabDUsZ(fslwa6=B9E^?*vK)-=J%qV(g>k0nuPN{)Hj#l9$uyDm0IMRS*(KzGG|F5- zG_{|9sU6j=8pwPBf_p`)h@v3cTX=0yzv2bf6yN}30{&kc3ulMGEhiwrLf3(oUT}K^6I*GS@EPR_ zX|zYjvZh!x)WlU$s@pf7fAQ*N|GN9%ZdAA)qY%tM&t8#;ZwK52yrqBF1<{^aW9ot% zX-P7Xg_sQD5e;q2Hp7F3FuH(^Gwgu#!MMy~A%v!Obu4Sfh&BVF&6#W{5ynigc||mu ziDZRb3t`-@=*LFU)<~G*kVSiNA4Y*Fz>1sc`-L$0*A6A+M1gy)th-IsA`$((J)2F( z`bV;n%nuX4JpPC+XTL>!HPfPsw>qToM!R9hpjw%4cv&bjlnvoVT1Z&}F27oGTe7#+ z_m@xG>+rYk^&s~WR1{B!!b>naNv4CSFgpaoG8qq#rUW;ro47$eRN5CpMLUvl>K)z} zKUflr$H@aS2={?6zW(~rE5%WF6uuSo;x0ycItCQm~2+EH4xH5h>#Z;2`Zt^S)m@yMgyFU9BCNrb<=OJUA9lz<8B(& zRdgNe9+3Jm`|nmY#o_VoGRp3=8IH_@r?AkyXeXg@pKwtqcc>~0PwyHffpYNg&&6ua z!q*XEF8Fx_A9NbcG3H@Js3z0k7nQ1c%gTRmnELL{kMmGXM1uMh)f{47NxPa@p0q;; zY8*+#2CxExYrN<5uD;gBWvz{?u>emr_N0^HkECs9ah&vlE+1YL!kN&XIt)@|s-p@H$gpbf&t%h>>j)Wlocq*2uKal8 zUx}n`=+|GCN5(SP6ZmgA(%`YI1UOJLi}gvNgsJQ5{MXgC{@sl{otSNlZ;zBGaP6n2 z`OkFMZWY0z-PS|8tq(42@5P3(%|%E2(sXh}&om%ZsK*_%jx;8nm9zF) z(M|ZX8n)?x#gFdAAJr#EvWz=f#Bp!@-J}6IOS4$u1EW+6M&bx%8T~Q?3I3}PiO;qW zASB-#U-+*ZsC;=A&1lw`Ng~wFG}B4qAV#xkFc!u63x%SpgufolJ+SJ&GNqnY=b1N| z3J*pHXeH0vbkp-EEx7diWZ3N!(nlX5ZE4w@J?QHg?zPNR-6!eP!ASz#6a4gRp zB-1M@WqJkVyvHVbCYpg8gxTd5P^Fqdu}4JoL_~$5N;7~Deqo=6MGq+uTV;WUk6^^g zreopVK9Y%suwI&=^13)6qPasxPdS=8;(D{#n#Ep6;u>y`DJlZXe2!OCgnnJZD)I!( z_v3nm#CnjtzeT)ZOCi7k!g@lb=&!~?1+x4eN&TLjs7Y?cl}bME1|%=%`Mi(R7mmw; zO$v)%;)b4r`TdKCz_$#t6nlaB#}YRAaS@$Ndfh0?CnU=&Mp^z#vb<=Nb^ z0|-}T7EL$c-<0bbvu^-9CFO(%qDyhsMwYq)QVJgE{h^3@K6oHH6@TPmUmEbh;2b(; zfya?C`6oo|7NzywRC_Yxy!ML%PK z3k4+IZY4Q83{4gikVtvp0r}#A2*ldQih9tmc^>HQZF9)^iuba?`PgB?#hohcmJC&0 z?beKC6i*#BV~oYKOnFmrt0{*o-p`!99-zy<3hl8k*uUZUEZW~l{iJ($%NUsQ=ShvE zk!Qn(VEyNBt(bh?nFoUx0Lm+2lO1HS7NVWPuX^K`z45Bvz~5@sn`+tL64e`kR;P&p zoahQfspsBQ$lg?_-c$%sD^%r(Z|YTV>IDqyRrRSC{?@48R0)48@c1SDRGf3ODhq%! zoy1bmxF;!P!2x1FkO7ym(K(mT5ehdgXa`r&4rM{>S%uqKe@V{w$pV|2vtl38G5;s4s%Ka#(s+h|!@FJwa5x z4W983yO6t|knx@_WUDlDL{9!!)!IzpT!X zdaX{xgd)Tea(1(~|5QEbV1?(crh|_7VUXB^#h;|BFwQ`hu`duV;2LB}$i^+gf|25t zI>eA?J%P<|X6iOKwDu0OmZoeBkd%h} ziQj$2HSo}zce{~CO_0I?SjQ7fK=oS;*_oQ|n5%hXnBrM27|yM9#5-kU4xI>p~ksT@R9#B&A`F$Q=8$xm7dMg%dcCg}_w z==#Ml;aa@O+ypw#+`jp?sRyTcmAN@K0^WThZE*8Ib7ZW!p^DFue@JA!#ShOgx9(CF zOt(TSrrYiK;gsA>H^AvgwY?z|h=@#2>a{%M^EctoBtH~j*T^%?E5vFzusrx;=5oc% z<%_wIQENA?Vl39?G5p#7EcG;`_+lj2x(y3N9z>zS$vmI}Yap&t248CyT#9S}TcwTa z)UaMv&sNDw9np@ZqEiuSu$Wf_nk{azB984CVGkoaR!olV^SEjIsG=08*+YC~dS;JM zkK)r=cV<0YZm`@7rP(l80OVP@w>Z(3%}E1JoG+*FCCZ?#ou*ax00w=Vt-R}mMf z2ni9S+6LS&W(2j*AHbP7z*11V0iHiVXH;mo3M9TykhmfTBtFHTt!AmOAjKo`AVWf~ zr$X9rAA2v+U$;Zg^d85^x`lpcunoT#78iRrknd8`cRJcI)c!iID=W3l5(4!0U7>Bl z{T4=g4hvB)`zwC9(Wzcm0uJSpy+<|FGU%REE&E)dmWjKr$(1r9=5>`aYqM+$MGaQ) z7ysTtoJH}w4&xqBJCNn`aBdP&FC$P9U5s8E|^!rgo zG?|DG#MnxJHlFc*;{2)|zaz%iK5_1yZq(}HL>QKgYsZZ-5-tSq6xmt$h4R3jU# z#(dJt$Q)pt@d{2g{eeM>D6uqxo$v&mfEpHO))k3LE#DTK{>QVwd-&&coB6o>m0rB~ zzJ~E}?DKmM+j8*dGwL5DVPN})l&^Kj?T@b5mLOr=MK{v=kkKzxOfwc<3ZMfgA}e6$ z>+62}#L(OSp`k))?wxL^P)VOy~QxL^`@ z8A|~|%M_j>Uy$K$*9~3&uo`hWwp}&2s@Mh|vL$aZ zM6d_AIc~4esN}C|_8Z<*s@_x!Z>m*qYK1qosyFa7ApG^K-mt&i8_|pg;uWgi6pNQE zQY)7UbRP`xI7l6dk^$9Pn-};6D+8=RhXq1{_^6o9@8l}T zk9$N!SIDSJe#X(UcQE;Jhb8%;h?`O`X33%etn-3}Tg23c$-FA?62U`Qzr~&+i2}k$ zU{*@2TcBgVhbU)|Q-z$bMHM+x^#?IkCJRJau{DxT$HKDhDLJv^`TFaxpJm_-#nQQO zdl)I4QB~|erTwmt0UH@OtzvSM$ zSpn$5{0J?;YDb>8!1e;KQg{fP?BOpq0HmsUZ=VnI%)Du6O?n)-NM zFw=hrgK6y5$C7}~PL#lrWiYyYu-^n1&RR{QIT=KIlAz>7y<>DO&GR-K+qP}nwr%^w zwr$(CZ6_zTZS%y*ll%8y>wQ1$*}Z0F_ny@?Reg1J)m6H*k_tc{mZ{zJR_$l2V6Q?m zeh8BF`4u6)Um5<@FSywqaFnD0)O!L*_TfYhwD~ym_*qD5taS=JKBm^hrec9M2HbEZ^a@%l*aRoIc*1)jjg z)G9rc$vqY7J%)sRnfqO&cA58%Ak_*`yCElvA-7VV4s`on3UhF^1gft$Z5nCo(|WWL z!zj?ZE&(p3P`f$PR)(|h6dq}e#1XuO^6{48l*fm^C~je;f-;0u)AO z%Ul3oCUd4flYBz9%6r;jutxd=Tkjn z8gaxLQO;oS^8LF>?Um}Z~^ zkK$EnrW;U z_u6y|uKMFcDG!jPXpD8i-|M>CW)r|}0(&4ywo&ht&TAL0a*_AAIrgY(K8RrVT9>_) z=2CP7)v3y2{YJ3{Yd!P!tr~Qz&=!C3ZT?PI>~PzkD{0~9-k4er`VawirZ_0QLrjaS zB`@^u&IO>x5SfxP41Q{ZXoJ2)JkHU#m9r+aamvLreFRBPZ850_V_Ra_V=u77rP&P1 zUFRq4j=q?b+ud~P-C0YDUAzkGp}*XFVCL(|-#n(Zf&4bLfj=ucpncOBWU{hWshM{1 zL{~D>NoG4DrIKlE&>9%l3;$Nqy8iY1<*k`Up;R-{^ou{l1B*$)cf2qmzGbh`p**3f z&uL4wegKP+cG;k>{P~F}F>uP`r?hrptPTn(PV3ho_TzDo{&32Z#D^0QO{Rl~J7Z1NW*U-O0?yW)&DyCt)PFEBX~76Cjz<+x6}9Tg~b z(hYX+@0b#!1m)kppp-g|zKfv6Q|~s8*tM5!pf>AAyas)?7!+HahTFl$Db*Vmqdu6} zG3uHF~1i@6*j7nyaBg~pYmVZFLU~P3W&ryv=$}MHplZJCXn!o{nid|CPrkAtg zWS`5K&?g#KD5QIYNh2gAQn_?e5@j%qQY|SZX#k=qB~9r}L?s(B-CuCGp5m?tCCr?z z2i=%_KZ$;4NO~&w&<{5lx2(#jTPnEMXRZDp0-)Kjivw=#zV1AqiaOYKb*M;bAjrjc z^F2R2(MgFD-LiIsL4GqpRl>v$8fqh`uNx1}((lg;ir!mo0-`gDmc_13tTY~PH!d8> zmoOy5bv0Ad13FHTfs?aLhDc5V@B$@YZlh7V^D_qcn5_P7H zpHYdcXPw6frBN<+tRO9FUSyx^*v>fDvYK<9W-#aAp2(a^Ih8uaf|eSa8ZAe~5Wf72 zU~hl|9KE@%M=^NA%~j_1BojR<(jawhCd_jgWVh*z7YM^4MJB?=; zucy1t4IK6R?LxfjBMa>k5V?xwv-t|Of#~C~Pxc`)`oAvvn;BWi)VkgzW|N&AAX#ImWN3JrB<4D(__1Zc4z4X;_ zg9y^wD>;~+ZhZA0D{Oo81QfU<7xe*RSNi2IMQckXF5Usx?Jan=b0j zn0Hc>PFI^w*PCAVs5XUFo6f4kNOzL0`?KUOMzniXS} z6|AE&;>fwvLJBJWwLl6Y7`nQ`a&P^x!tzgps6vU8n&8=fQXRP7#|Nx-R*oc@;}|#+ zWsfS^36-1aG*WwZ+x9xLd{TSvP>o?FH{r+^mG2-`a`e~_7WJve3#0Fu(9Jc6EicCK zmxOtSQyRcdXc12DNt%GXd`JUG9kBt8R*-T@W#32*#Ci}s!9#0E_dJF_FtpP7F-;(o zv#3?h&DDQ`4T~mxw{IE$d1ZqBlNNLEUAJ4H{NSBVAXVVoi{Bm1zS}&!de}66G=&t9 z-cG3^1;9W(vV}6hyX=*pG2VW;*ZRYH`O<;*2%$bj?9G_;pf;tf!zh1W?QOXe>5)Kv zBHGJ#T)pjtBEwY3TSt_+IiD-c`7p@M7=DTA?WDX1u%Rl7zdXzcnvZzfsDU_-f`F@n zJcQyt+D!Q*12|7@x{hM6%A{#BLM_Un<7=9rT&L2ZT9-VC(vE4%y$_a9ehinRax9mv za_sv1&3H zKkRpjI9AtsN^l8Q! z%KQgaZ*jaTQfZO0Cz5J0Vj$B09L8jXgscDBhAgef{*4{%@sDWG0u#$jH<x@ylf1l3@-L{A!(EwND&KhWHXK2XOpH?Sd`%wmd=G&N@UAzk$T@ z`rP=JG<&c3C5<hQd)TZtQD1Iahw~KR`bPsM99I#0gIlM)Ch{?I2qI$&Dy1Nc74k zXjpGdaZPQQ2WSTA4?b7vI`5SH`Li6vopbp@1FAUFclzqOrzW<^xTrQ@c6$0c`wNdwvL`+0iT` zwcw;iFCTD%+$Q5BGbDaWhi!wYrf_>lF890Ly^2GSQkJr9KBe>@%1Wf1xORlPGxuC6 zb*yt~r#g*`g@X#r(FEh|8?x`~No^!_^X$HZx`WTKlK+B+~3(jHgGKUPfTox?;JwNbH3CV?9t~6bHqSLn3hrklP=t88I>!03gO;M5reO_(vPx(KyS!w zDuw{E9hrLY7e_Z>X~0z2ZV8USUmGyNoJ3u!svFJX!{C}&1{U-U|7(1aX~OX|`XqU} z+efx>Ek4ZyxAPQCXl6kcF$yPz3W#d`4*IMSPHnKg&YSWqjmwMWArtr>D)uI^8XW#5 zu*NdjHjBzDpzx-Q7*l(0Su3WJzV>@26$ z|It3?qXHCJ)A9wKD}w`7Fl}H4d}0p+I>UzpQ6O!k_TQOV6wIuz=(>#4WLX?Ph!C4* zukcrzz$?GNmB_gX&?@&-rufh<^aP%>Vr5LH5y+{g68A3Z0k>+okZrk|Hd)S^00K)= zZI?y+Ua8nwg7BkW;`UxkD|2~mQrCdm_=mbfO2JsG6Xg*`eS+JYo`;2QtOyxk#CH(6 zf4u;3Xw6AU_}IQdqq2G;Ud?7)7R+KWC(rO&+Vow+5?zJl{Vg)r6Ih3U^`q%$!RD4Q z64?(%sG?$$Py7?1ZDgxlXJ$ z#OOt=Y#+-WN1tybB%hDYfq0f;SO)av9tEVkaWn~>=Q2=(ZVUI7lrqMFcrBS#*z;fz z=C!Dndt=iC!R0ipG*X#NqHsYHAS8vv9#wv26gNCgL?uEK%^p?H4;Yr4CxL9gkg6^q z_JoGdG0=L2I|RwG#{a4awmWP`70jsqjReVtkHa>EYo^ZR`)D^_`JsN7rN&3Na==>5 zb!K~Yy8HcS1Az*X(Zf@HcWYF%Cgzu*#ofe7jqywE4ZI;xpCZeWJ%^&v2Q%&G8Y8R0 z{{T+(*%A|LAI32XbziGN1qEH7BgeQ(D<1_T z+2MG3L{s%Bo>ZNc%h5sYdo|;%{DCW8S+&LWI=_y_rXH`Jz=)^bd2jhM`zcs3O>QQv z2#$t)!WjSt707_Tfr`^(Eqi4w9%mle zux2z9Vo;6eb?A$v7j2xH39o^S{}(;P=z^pD`sGx5Xw=TFH8&xK#5RBPn3IV6@QsVC zNejz<*4a9}F{e_0-PS{RaRxf zZyt5XZ*S?kZywkVH>y3A#11rg{zO+@{=GqUv|T2_gRhAnzD^DX{|BXXXkEvfiMT8VO zSKG2_`^mh?>Wv7y6baueY+qTR2U~I2wPDRzRfNJ4R9(wmUM-gAmTdA2BGiBNsvjx`qrgG_}Bo;#^&|;;lqL(ueqowC)KuCkH z1^Hd3>Y_j!#w?THKQqTV^D8&L!y&q4X^X4e4u$qaKliJ#T_G?6f1klExQr~@^iZ`c zpAyj38m=}vGF;d-_*eF0EfN*ZHC|K5SL4|Jff^2_nX{*>w#wYu+-R>>?d|Y>W<&hD z&g3}Ru(U2RxH+N4Y&s9ercmn8UB})%6R{ed;iWK%)&RbD z97^^%dXB(lv#a4Hd1DlaEH$egJ1PzH6Rq)wdql*~h3eYwnQohZ}>R}x$J!cB|V zQ*Ta1kmybEv0EkL(X)YUeruwKCNBM0y&(iJva7cac4GvX+pU?|5<6D;Sy~QY+wHk? z{R654B2paPRy|A(d6qS3HTuB{(pXf}ZLLTu|HZuE*3@>cyYhX&eq+2GL zBk~KO4Q?8LQD;@sFR-8barz5LQ>Fw49PudBT~$JvkHUY`>j?_p+9WxskaF?|&v0Ej zjvUR;4B28^+@1n#$_%xt7*f{<8br(tD3RuEVhdxu-Y*2}xBPQlv*sUpZBvSWuM36Z@Sd<9{l3n(v^aPH{aY=7Q#)jsSF0huiC!9tm1(rj4cmOG@@C=5Z>|nrN&0DIhhZ-{B zO+;pti%GO>-6NI=TudH;-YH39jvU~O*T^}__q7q}=v?;LWZ6FCNo0(>HbsyJ5@hLo z(d(_K#V7kghz8&g^Fd4c53~_2LztU>$msfY_xdlSp6YY z6Py{A!*EcBPs70Rf@%?n0X?f(9ZEoNH4@TzlLNGin1~+iX8fE%rPL;w-C+3@^?w!bPBHzTMgtzwR_II+=Ia+DQQMJKGF8#h)cYhlqb)3~ zOPjR&OB-u_)T$@+-|6{KjQi{XdbIY3VRUp_4`Y}y5^9l2CK_9wJ?FB)Xlv`2v|w~b zZ_f1kgK9C)zH>Gr-gB@v{vDF_kKSxtzva-^FgqaV3=K>} z=~Bt8V-zu*5MqHg1};L?V>gt!+r* zY~Z9@Sz2fv4368pP(KzV4weQ2m%03{hH})vr3Ws!RG7jT8oDR5JGsJ`%4}1KGnCbj zWKNb;IpR58yw;OBT|h-nmT>clovu0-b-eb(^fN_i!I;XZlW{Q?)>LQ7lQqabQA_Ql z+)ns>f*6wyE+Atg+dVD+ChA0K4xtulkj`1^M2o&bj^O-7b)wOqYN@t#OvnSbZ{ZZt z#U?8qQ}7+EKwMx$EbZ-LvpQYM38sj0%?bH&{7_{AG??zmZW=V;2~`W=M$vj< zpPtAx--pv`TW=s?rNYM02BA&|ni7Ym4q##TnmP;pg))j3{FxtI0>@PHh^(!2Leo_} zCF!i3F?3eVSv;%k4&;N!Il8`W?&1l_jgktr^wsO-kp4P=txLrr4MPD_&Hi4d=-O_0b+U$4XTp4zl z3V}ToWMD)i8YbV9j z7;4|%WBL8EjKgH}xh9s)t12i*|5EU$jy_nsgV|D9|5BiN`PN$f`DY>Z0)Ni~N}AU& zo+yha9=DigG@soLh&e41tZ}gt9ih>^BmC$?BL0LVq+uT;oDk;(i2Y)QZ_P z@Qx7Xz!Pj&2LVq)v(8-rDDeDy+5!kd$fC84R;@U{MAk_@mhCMU=gjr ztaNsSFGvNjn1eGa7mb=RR2<*vYj`Bqka4>(L5^)XNrSromLggNB<2S#W`{lhKS0OA z&W~z6ALKBef6vO^qo4T;=<-+OZ!fZT+mH6U7WXAO`I8|I-E5X=67-5ag(t-pG=W2W z$3zZJK_VETHwb`RgcUusLN(L(w(9!6-^H(_i}GXMPXnkJ1g=9M<*1acfRpQvCaSc5 z3W@7%zb@rS9=za2ex&7GQf4KuMo8M=_}fl5o@x8x+2vtYYwKbTPoS5!J_%Q-ooG)u zYSRy2jqs+m8Ot0;vM13WO?DzV)2L5$dehT1yH1HL)g48&tH?IOemx6hmOhV+XGNIa z%2BRxycAYQHn)=55#W$xXfbV~(pd8si9muYa$58&K*|G6h%t55&(E1`A+h&dlte4W zG1aW&@?$Mgc!(hv#YI!sGL!oc7aKXv!-TiF&dJ29H^t}n)`6Qk?YKuWM>1Sf0p3~7 z3#B8RmYK{$30Ai>s^wCW-OaKGCE1895uCRqZ8y?DXm329@f6hPvfTt8g^l{tO8&>o zJW1csRdTgztIIlFl#w2?G-fb0bT$GVa>jSE@chN(GxD8KiYJHPFsFV%F+clZJ7bJz ze`!{Rx=KqTY@6B7%^HaO`tiGo>c%;S$Gv`xH!!fYmjaGkjI2p=Vnc`n2VCM5s5vlG zSmPKRn@xwXW!Sc?=&;WOX6kI(rz&jPmlgA0i=A+wf}nFCf~>Egf|#8Uz>uOW6-!8B z+GH2pJq-I}4-E$m7D6OQVPt3>XP}PdVyHXtZI2jG8`&LE|L5YgPZ!wHAG{Vsf`?|~ z+~iilU^q>Bh*+f&bwbLai~{;g)XvY=iUwH(e6p-ao5*A1e0dJ3!i&+Hr%|p4Sd-De zxMrrqQFWOCslyMifr744u5X~|NC7J=PW>99AjomN*Of7Sdp0i6fWz25J6cnpA;o#<}3(EYiK598=n472yp41tPk1o`x7Fxt^Wo`^`M=%IodW_6WMr5?D=Y z$3LX~1I?Qa(w&qPcLKV%uEvw+_hsx+ztC5JeGxmAU5X7r_oMDPEYDDEJP(kr#GN`oL_R3+9TK zi2|7&JDAO#uHWqo5$$gUXHAL$V4o>_{HywV={?qPU(uMhRX}${hcm2QU%M zO`DpX^a&$C9I3D@E-p_8R#IgN61em5MKG|}wocu6Oqiss;SC~k@}G zetB=+S1sC4T_O5sj%OY+opvYpT;$rZ=+O!*lM^z?QO|6kI6i@+dEitrssV@AkFSbF|7-+%0>zb37T&hPj*h4%tovWs|;^S zrmNj28|$p<6BC#RbDXLH`EGQGUrB*|RoTM4%m!bs4n7meUb2t2H)U>N4MkxG&B)33 z4k#%L%rM7iFYBCyFY5pdAE!g-87W=`FY^?RSh+U(_G?U=5}{F)^-J7E6~Jp;WK}K| z(YPQLH?K`$KB$@4lv)*GasRae>j{#)2e_>BeFvFQ2`)K5qA%V}IJM^|&_Ve3nQqUU zznrA%<0i8%70Y;K_NB|`bsSd1mg!|#=QoxEks1E$3G!Y9ec?y4ruPU- za+W6B;K~dJTT%;x>8%be6XIduo&-tTb0s2HFm0-SX%mbRBP#Cf9OH$!WARX94zaYNy#p0d0yk*W-~OWO)Y;GTLs1Btes4j^C%1@n`8=|6o$+f`%%2cvXc zUNebwQp98nh`xXHtI7OXvpc4%7J`~N)wHbO#v!Q_NzE2-g4g@sNmhTOIL%cnV@vWS zFPqb4yRy}y*HL~TIZfGMxS4EsjVhp2FEBe|gL3B$SW0YyTt_V+wplP@mNc-ee}jyj zl31_v0`wO+Xq^7glr%&YKZp-9Nt1KyuhOwHaQ=%b0T^Oe`m6-wuZj*@lkd%+Z4cyA zMnTb-DJK*46AH3n1D2D6HYe|Ew<0X54ngU?VK_-LFtY9T4&+Z#d(Ig9T-<)amJ=MT z|E5>Mac{@&ei_4*z%IxIc+FyBv5Y3?`9j;0BZ4?Ay<@>7fZ>!Uqh8i#Rj+KDRIda! zx`{(*Q_9Jg_uquLQz?uU8PN>oigrNOx&(P<*C9CABp_yg^C0n_UMW5-eQ=LnC99EZ zKs`VDIB2p-$hUFxxNP}JPRzHFZ)Z(h@xn2$Ww7mO>=BPxkBM(M0szDCe}N8$?$n2b znbISeV3?z=4*Fe4Hd+>kqB9o)7WM2VGx7uy${16Y&$5sjb3lD#vQlN*aO!%8^c3nc zU@OcjUB@e-ZO=xA7C}2S=oMH30o!w9m68KvPk0r6*%+Inqw0^jU{P?A?kS1!g=|(T z{;L4UJm=agEFWE!xq&RdVTP3y)ZRzCu7&1oxIP<{YBHxcR$M}l5C)O7;b`PS{2L0Q zC_-{HV&CP!Qqlm;aZZ}G@7hY#%Q+H{;3tCjFhA|9gpQ#DNY0JN(jN;BO9@^u1Y5=x z9c9ab-6^n+R78W$t#!L@@WPWHDrnxY0;`Q{J2+==sK;j5K1Lw=gbX`UW0-U&&pQ>s znfU@<%QXJR9gF0RlNHh@4%smt$E*$(0zLeIwvUzUavfnF%;Jq~drB4D_sWd??Q74= zx@f-+#^4JJ0=cYeBR4uw3IguPHvoUe1?xEQgTL5!F=~%Xp@TcPdgp|Dl>({_&RTAN{=EXXrbP21(U~#}DcMC>_$PrY3gjLMcVKa+1 z*qJMgiS|*Yv=GVLn5u29IqDqBzzp$2WJEYb7lZZIUY20rZ0T~EDB6Ea`SLlP^wR6~ zwrS1>*O0Hxay>?r@s%#-Gz}n!nj|Pm7OpEsBQgd8ivFhZ3DB*b7G)Lwc`6A=H)7wa z!i%k=SMV387hzqm+EbaToAP+4A6Ze7?l*J~eJ9!4_fYvahEMmH3dSnL&gwV6A%y+8 z(yLDX!|jZ*pvlxwxmV5TEY)dy_eyxRR+J47_A2^nj2 zHYY_*>uH{3u4o?WZOsZDJjW0u?dZdH9(HhyEjjK^?tcDf(+R}Tv_5&DCLy|5rQtUw z{|ao_5;vX)+w*D94gQQ0W-Jpvc# zP=iU-2XNH4z8_d_bGY9Y3AqNORvW8BHk^|ha^hkwAjpb{QCVmQpE3upV9XNfAoxWDXZQD>0-!{)rO}sC`kjEFw~>4XL1j)Y_Ai*NAW^T!HYR6lNUa0|Sr?rEu!ABBH2h#5AvW03G_A15 zAq5j`b{r<%vSBQhl^-Qi-~Fz2A)RqXGHhc=7zR^qq}du-(tzR+`WsK?#v`YP#tgiI zgIUMJ7-+sYzv%z0DsRVRT($&c#H=ceq@b7` z;E*XE?&FZ+>2GjmGl%qZO&xhs50ox7@yJ4ierDyc%qdY#sPR+6lmoWcHm&chl$cGILU`q$bng_Si z;TkCFhig|YbjFl2J2?$6q5x&l99qCEG`F=Vv^}*9zC8f!+j%J$Oe!DTZPjI9@eof_ zxz#|jXq@ik8w5R4Ha_%>5ZqY=#U`aX%B#jGK5%<~V#RAUijV9;gDHH^v%vuIW;=l@ z@dLHkc2}$=3-d^l?NAtg5%h(5pnM*Xb7wGR+U)KZ^@Xr+065`AEt-=@n+tl2wB>i`(@l{4s zVDH4uT^@)4!yW=6wx{na5*$R(OJI+$C%;2bTBjS$zki#7(qABz!AY3yx1A3U8M9S^ zf^KqHol>yU_$#C2^$v`C41GYr_EIT8z;w{bQ^fQbdJ!A>~t^WjCmW7LEMB#F@= zBE?QBaY*=OEmPw4r@jV>mDftu#sk8BAE=#<5)FP)Apo@3j={oU#lcdF``7LNNrsI< z-=>%Ad%7@P9CoV6Y~lrVqL)s;igkIe-iXP~(j7)`4O( zE-}L+g(Ff)z&|W`>$ZARjKKe$4xHVV{_wu)KhgO61vWw>s09Js{B@Chj!gms{CA>G z8~|`be;IiFKd~U}y`n#zJNeC@*o9}&A_zS5%Mto>=b!_%_oe?HyaYT2>-Fb*AWiZS zAog}Le^0fYh5+2O5B-2>c+1#2$Y@I~06MwZG|jY+RB;~tb#A3hbulygm`3B+vTGHP zb`Ny!N=1{<&PWU}Cz0Os$WvmVpuos&m>XI)1JH#Kvz2PSVw5&))t2(}N zVm94dPXe6=(b}nvzc#=5z|C1`!w|~ic1(6hFmaQ5fnr7=eEI4`kx~r!qvubA1IIr! z+kD3`X#v!6_)``5QGI&KE7It@G~g}E?8FUyK~Xwot`?&vKrboj_riX%A2t5F%GCmWhCY-+fa~ z0~W!(@_)k*1@Tax001OkL${_^DD*u61rhs^%IA}dMNPnA8$(O*T45}(S1}F^!Nd9n zIN%qA1LT2z9gmODy^nw}#ps?itNDKe-v$)fmh?*>H*g|Jiww=B z?}*{tTU?@Vd9K<*!>7!4_C%uw1@}V^GVObgka->#+ONxKXH9upL`c)g|1W=C$jjp7 zoXWy>E|Gs%^GCklDb-kjK=}U~YkZ{80$?Dz^?3jgBHIJk=Tg|;rznAkRLrB6%WdRf z_UBUU+|nU(z=^xKYBt^WW>)Xp9iDf(s5JrJw&Tdqh;am#X1Cl`w~FwCfxGjiy*9Iq zOT8gaWnY%-^7P%Pkt+W9yi`6few#YntR&wr9M^_hEo*Cb7Lg8HcKmnFxw2ZOA>fl3 zbh;5}21Fa6JtB%YODZ>GWvW9Mx2fu?CDkPgNxo^zP0uW`OfqxTiPX)J?PY;!ww+Kk zJdm3+i+CpBc_!^l8JTR`2bkHDTNEq}@9IW4%Q;ZU{*qUdi0X4*@M)&@CU#EGo6L-_ zO@_mdKLWE?=JT72fqW7MJ2eg9y8$c8=(pRy1+!7sqk{4n2Rp^j#>hW#)5@@8Oq7Pl z5MLDtcT~v$-z%1f^&1C@Zf6AGLS9-l#Hrq7od2YB7Gx&2B zt@2~ckr<)l=}z`j66WJU&+C2z{6;ojL=YF`-4!nlpNoI;+oAW)Z_6wDx5qKP0{tkZ zz7i5#2DdS`%ji=+#gaPaCcZL_m5d0$oiQAsow4TN(;Po}={QO4495g^0J|*Sy=S3N zq_FMdHB}pkE=A>UQd&a(T3_wc(koh8-1!B=mTVu}*ynofKANK(-8q>(ok7L$`prv6 zN2ycL7x@UJnS!#b!5iZD_{~W0mwFf^E8Uc$;UFe%bmG>K2!YMZg%S#-P5@A>3 zq=-Xz6?5|KqC%Z@HY7>!R0BgRzen=dH{CF>dl095`sKmm4RKL`QXG0}tE z(E(`!Il@VRk6#E8_`ChlgV^h#_&wdq9SksvKEh)_DG5Hc-7w8{s7q4m*h^Bn$AC^p*B)|mNF))M@gq(%MBDB!Q&{1lq1w>bH3ei54C{Poc}%EFAU@RvJJmHkwTeE{z1rWsI`!!! z%GkHo|7pbhsQrsAFo5m?z+i!4Gr>JYf7Jvb-%)_@g-^v+_4RLV^wcq~A*nxrdsS(b z?$Z=3;1c_UC*bjZhv;q*C?FNFf-B(Q1%iOzLFE~T=I<|+eOZ+t?h@$M$o^+U0Vmln z7EizWp#Ud`%pmgL@W&ALay}9Ef<6%d;)w1J6hU^-1%2TjJOvT<416K(^n4-eS202Q zAES=V{z=vSpKiEP=RfCeVf7v00I4({kGj+n-kGqb#ApfmroPws!eH~vEH7x$x>T9o zXEY-8gWEA-BJ7EU{eEcog^pI6N$~Uy*pbn;@x2fTY~TUC_x}^eTj(ELpjWvJ6bJ%5 z;c@dDGi-=GZc%(k?fV~~y=u||H4gCza8p;hlfK|^E|9%UDnJl_`UE#z)m$^mXRPAO zmZTd|#S-p*t1Rnl-%2QXxX*z1z|1$Z142n2ChkRW%u zWzek=Ft-p=8R)jswF@%0MkKebxi|hBT-&X|TsP#PQ{01qB>2p&z@V{ckQ zzsCQBfUw6&d;UVylbCTbj2ZKAZ^LSkR7s`?*lEK8F2>@J`i_O*611-oW!QD8GFe`;S?dzgr_`kX zU2;{wNmFo*wIQcZ;?=`0)B2!0r4Mt4jVTwb^u`5`$Vv{>BhzjG$ch)OKqY-7?yg;g zFAQI;fA>v$VXa0bZ>Vj9%NPP3@8)EZElhtkt3CkfVWk_Ax;Z ze*Xq|U`%r(D`gDpws<4Q41T9}k>u7Gvqp77sMNV7fMAuVIJ>>hSDKlvTBfq+WYq80Cd za`0BAXh&L>DpH%|XUXwK(b;(iw?EQQSdc9uiqO4Azi8zGp{77Q`j4+Ur9KtYUD<`T zghlt4dP_W$5TvTQGLX#7f^59xM+OCmQ|_^&w;MHgk{x+ zzN4PF|Ezz_oCH?;2>FKXRy`C9d8zWLAp2#ZOPk{VLe52I(@(k5{0sqUo=oZY96oY$ zwmx=|oheV%Sfsw|<(r$Ru@Fp%zQr=>0vy`D#f0hGr#Z=~Yd0viEAI7|Ti8$^@_UN$ z-I|t0jMfJ)*8QAniAnsH&I-G=HdK=}zZf2JCr}7eeZU(^3(vU+s}LQm$6LoExBN5y z$c3iV#4W(t+m?opzBb{t&^vDROC^dt_wJ^s85_$_Im}u;J_`*pP1$umTEaecYtshT zV?o+;_A|cfl;_!{XYL=pc*CFNTba^bNRt=tIy4qui-|l6n$MZ0yrqmUnq}P?X0JgC zgkHJcwl{@XB)_4i?J71b-T~0-aqG{%AmqyR_83MI9sRg)TF4dX?+N58U0iIrltL54yfs2?P>{w zYWxRD3+?SSPLE>?{}z(^Bo2tD@OQn;ypjf5cK$!y_onA4+SR*=LKm=W*_4cjNSbXE zxAvBkRFNrl;r0p!*%8E)T{QfnwedBMQP+ z1La}P0A%+1BGf-_rkw$l+x?&0%~!mSvAERXmv#roNF@gGh}{cIH_(gI-!b)Cxm3a^ zsp_n<7tY7lYKL*275$#3UB39C0&`Lv`z?}Y=p?POyTxQ~VbaCVe6Y*Y=)%IulR8fF zWnDzA;?<$qgg&6Kb@A&>*U;jm^^|LBtt#i7U**|Ile4kI`%4n~kq*n|77G(CqA6?T zZlL~CVXosbWW7tPZYG|h`IR&AJ>@~1apP>ok+jB=98Jmm(S-~=v3#zQxNM?CJfvvK zRfQ#6s!pm59EACFFoN;V;>?9va{FCH-;AMhN};L~={#V`zOKSsP=!;G*1D$Zy#oeY zOsv&b0qes{Nqa2p^==zdZ5l*B0ZT3hmh6LJB{M;>XzrWPBbZn6%0^OmGLwuc!e!zK z<8Yy3>4_eHeex;kTndJna1ryEIfqTVp*8l2Gz<+Ri|#_j?8SPkYmr#yOh#(EXKS%S z<>fIb6z8|XwTM{7<)`-nbOdO`bq44>ihI*OXV}`^nLC&l|7b9Txf%MvLgsz?a-V1N zr3gfV;>`HW;FddLvFUd>E*NuHfU^;GY=Mus7U#AF-`;#S2JRodPD`33Ihz>-V6Bbj zpX<)+I-Wfxolwmt3!u=hsCz!sx5^V0zruBkL|!ei!}mw_PP1;W$x>6g5}wlb5679K zW?z>_n7jbX9GP&u6V0UUh$#Xqs}e5+xl@nr^W^;u7AaJ@u{I3O21pXP2jq5So-(s{ zPXrtD%o+X9fG&0Or9c~ib(jYL2#hKBxCASP^3l5G)xdmh*xkc$*gIA?W~L@e6hd2RR z+t!+)(T`4T0X$%jqy)}mf_MYC9aN4}!gzf~rZ%8r*dri>PX_eu6W{T1$2J-3eo2uz`&r2vAt(^M9JThA|5FOj{=#3Ghh(`PyPnc z9y~;^+VNF_t^r%n4-62oj(B=Y9JhZEuDG+pTsjTG!qJZw31|rvT!G;V0K?`0{=p)2 z8{$LgB`@3oj^|-o4kzw%z%=3>Va3-47=YhQE0I zUvvBaZ<>DV`{RHFu(BEgWts&T0A=R)l`=p$?}B`>3i`<^=px5Z=Wgt)RX#t zKg`wRUsV~Wz0W8Y(1=;6f{h~L(QtatZOJ{ zu17A=s3n)McRwruql;dqW5-gC!9JLBl&aW{SwVqo{1Zo`TB3n$x7~8z`0>W~PW5id zdenBDX1#bp{i*P!SBu`|cDuiA(q9E3kSS#}2449iZMY^%Tew4o)$k;t*#%5BiDc7l>q%) z-5_TiRO4n?^Yi|vJllhFw$Sw^>*}Qi+TmfTq7Gc3>_q|6?aU)Yl@8i4`yEi_0LSrG zBsLFml{l=S$Iqa{^i1gy?tb7 z{S2)|AflDu6!mPJQqi? z3KNB7_{+S3OUA(~H+Qtc zo>}k~{)3h+fSExP;oNm-4^sDOcgz$6)<=({*M~M6@UT8vx5och*mVXqp={wG5I}mQ zh)55ihu#%1v;+bKyr2?-hF$^z1f(fQNd&2p2m&fK5~LWVC;}G<(orNdsfuvHASfUz zig@FjJL8=pA7(zA+nD247hu=MUzF zp;mDWU{JHT_sT{{2;&iQuNK=jF{-65Y2(xE`kCiyZ0D#FSd!pNmo1c(1p3l*aYy@= zCwkFokEz7jCdisZ?#YyL6ERPCQDZ-ZZLHG4ttFSqJwh?vQ*IU!dph=XJUGlCjQP?{DA+7PLk#HV2WQ6?Ots2vu+lyG$ zYD6{Xx*_}xz%On*ZZy+bqzTc={!wy9wv(;Afr!%oP_V!Q(h7Uy#iWB#J6^1NuBu4J z%C1W|>~@=HjlFW-)R3+o__96R5eI(`nLwl5Wn8hSV^R}-sF`EVICVHgO*wz^2+kAE zq*r!iu`cAFTsZ>X?ExgSxj1FYO~aTfPJ_0}n$V)Bt<&Xhl9GtSe1d0HXR4O>+LG-wNc&7i;lLbjc1 zj{(Dr?M?F!Q|!G@fJ#TIG)Xrs&b)}JOfyg_!sU(dZ-WegUGVt8rY$!Rxe-Keav9+Y zP^kF^*f_OeZZZDKuE}XXs*OD8K!G|w8S|Fi5xvKb$|4~$7_{nR1H(Q1F81@!_+hMy zC%)S{5)8C}6d;dpQE*T21rr*TMar^BfqbjjaEX;&j-tTtT2$7dTIHQ>9#WhaMJM{g zZjZEYPv?K8xW>}tLZEv6QL4z6Yo^BGtW~RX>a3SMKNZ1@gMhe%9WjDUZ?h6ZV!_>t zwSUMg|5)SZ{0uN(^8C)V#AkvB`tt=yyq9c`xmgJ|Olrf*hv!7Ni@($KpX#qaIOcrH z!ViEMXcC?N)#ERb}HpHY}Gbzi#r`LP0>Wf+E808__5Olw7nW6359miH~ishHkT#w&&I)9?&| z9wYdgxKi2qlGH2Vpza>T97rknLJ2fp7^Gs=A0aL`gh{QvD;#)M4m(O7vg8VVO4=W_ z*%l_@75B6Th;TFb_8~R6`lzT^M)B;ExD_VkXHm8J?e{x)JKTa!s=dqcZ2$as!#+2& zb9R-0j0DwI7*3UGUBIz9s~_#|%mDT*C zWE-eU`?%iPA@J0F&me8k<`a`() z3Nmkvr09En-cmVTF??YxNTgQfQ3e6}*A$2y@pHS2_f+5BVEyIR>w^(}XWjRZlfi%dmH1s?|1;*xX5Zb+r}<3&!So;YeY&;hAWw`R zv8b9;L#)TpHjw;EeFn<94imLO^|kVb4LNV{ORfs<#;X+Q!>8X0dQV0-fAcTR^KUAP z;PVa^&0hpoxz%k>;`=`!vwUUq+|>kBdym#zMn5vZA&sL_Wxf{T@>iI%JU?!yzquMd z87z4KX+u##qTa*S9@PhU)1Df!Pd*=&-jz#L*qxJDR4u&{_#LQYx0^djGd50mIdf;L zaiLwpTrYTDCILH-#>Yd^?_5N7?F=@i3)+<9veS-$(JgO(0#No`+*t-LTx22uumoaf z`Rp7b0B&w>Ku*L2bVXD?&=Lir^%n#S%~Sy zLj*eZ;a;m*gZVsW?3+St#BF%3#Nu#g!@cz`4i7@Rv?pSVXfv43SbO3l-my9`%87ju z{?RkzB$@REb>U1G0!Hr(u-EDKepr@rzi>0(FT6<6iY7%ce)bSSX@(J!-!tZq(YqU` zJzPe__tS4l>2B_i=9or%=<&Bv6E|zcoU(~?JOquJtPTZg5uRtU(fbFLNKt4Jo|T>H zSGFg^tNFBRZ*t0$QX_nmynMk)A^abcJ80Eobaw%CFqQp7x2a&SG)&>r5?dd)Hv1(( zL&20;;@vZy&cycU$NgN-zm+7l?s)#7RtPk_2R&( zbyWRe=0|%wzPdv{^D7p=*i`3yW2?!ha-Ld~yvH;f{yE-2Q){YnVFbTn9NXwA4l@HQ zKJZAbmmm}7DGwv1b#-m*{6y%3xJO`z)bfpb*A4@H*GhP$annmko^pA-_0*8)`(Yon zPX^wwdf5F9rfa8yaVaK8KW1Fq2`P>gi|8O3jZ7E;v)RSvf}iQtnfNNIwP%?M}Zy z?>HxT_ue4@pq2~30zKOy5x{TQ|C87Qp0mnv# wMTSM-{Ufj;AyC{!@Bi-d-^2Z4(r;N~G4KEJ3T4j;{1tJCRmxcHe8w;DZ}|$uT>t<8 diff --git a/plc-program/V4/Schauanlage-Elektropneumatik.mnp b/plc-program/V4/Schauanlage-Elektropneumatik.mnp new file mode 100755 index 0000000000000000000000000000000000000000..7b21fb31e9b76c566c41e1c4e4b92ac17d1d47b8 GIT binary patch literal 35948 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 Guj;?WzXEdr literal 0 HcmV?d00001 diff --git a/plc-program/V4/notizen b/plc-program/V4/notizen new file mode 100755 index 0000000..176b031 --- /dev/null +++ b/plc-program/V4/notizen @@ -0,0 +1,2 @@ +manual inhibitor von Pu2 ist inkorrekterweise auf I10 statt I11 gesetzt - wurde in V5 gefixt + diff --git a/plc-program/V5/Schauanlage-Elektropneumatik_V5.mnp b/plc-program/V5/Schauanlage-Elektropneumatik_V5.mnp new file mode 100755 index 0000000000000000000000000000000000000000..eca8dc1c9b90a27fe2f7d9eaa202ab9720fb65e2 GIT binary patch literal 35991 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 Mr1YclL)tIzzvXTC>;M1& literal 0 HcmV?d00001 diff --git a/plc-program/network-inputs-udf.lma b/plc-program/network-inputs-udf.lma old mode 100644 new mode 100755 diff --git a/settings.gradle b/settings.gradle old mode 100644 new mode 100755