From 80f4c9de91a592adee4188df6a42321cdb198c8d Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Sun, 6 Dec 2020 22:53:02 +0100 Subject: [PATCH 1/5] Moved modbus transport from addons to core Signed-off-by: Kai Kreuzer --- .../e3dc/internal/dto/DataConverter.java | 4 +- .../e3dc/internal/dto/EmergencyBlock.java | 2 +- .../modbus/e3dc/internal/dto/InfoBlock.java | 2 +- .../modbus/e3dc/internal/dto/PowerBlock.java | 2 +- .../modbus/e3dc/internal/dto/StringBlock.java | 2 +- .../internal/handler/E3DCThingHandler.java | 12 +- .../handler/E3DCWallboxThingHandler.java | 12 +- .../modbus/e3dc/internal/modbus/Parser.java | 4 +- .../handler/E3DCHandlerStateTest.java | 8 +- .../modbus/e3dc/util/DataConverterTest.java | 2 +- .../internal/HeliosEasyControlsHandler.java | 14 +- .../internal/PreparePayloadTest.java | 2 +- .../handler/StiebelEltronHandler.java | 16 +- .../internal/parser/AbstractBaseParser.java | 6 +- .../internal/parser/EnergyBlockParser.java | 2 +- .../parser/SystemInfromationBlockParser.java | 2 +- .../parser/SystemParameterBlockParser.java | 2 +- .../parser/SystemStateBlockParser.java | 2 +- .../modbus/studer/internal/StuderHandler.java | 16 +- .../discovery/SunspecDiscoveryProcess.java | 16 +- .../handler/AbstractSunSpecHandler.java | 12 +- .../internal/handler/InverterHandler.java | 2 +- .../internal/handler/MeterHandler.java | 2 +- .../internal/parser/AbstractBaseParser.java | 6 +- .../internal/parser/CommonModelParser.java | 4 +- .../internal/parser/InverterModelParser.java | 2 +- .../internal/parser/MeterModelParser.java | 2 +- .../internal/parser/SunspecParser.java | 2 +- bundles/org.openhab.binding.modbus/pom.xml | 9 - .../handler/BaseModbusThingHandler.java | 14 +- .../handler/ModbusEndpointThingHandler.java | 2 +- .../handler/ModbusPollerThingHandler.java | 18 +- .../ModbusBindingConstantsInternal.java | 2 +- .../modbus/internal/ModbusHandlerFactory.java | 2 +- .../AbstractModbusEndpointThingHandler.java | 8 +- .../handler/ModbusDataThingHandler.java | 34 +- .../handler/ModbusSerialThingHandler.java | 6 +- .../handler/ModbusTcpThingHandler.java | 6 +- .../org.openhab.io.transport.modbus/NOTICE | 20 - .../org.openhab.io.transport.modbus/README.md | 3 - .../org.openhab.io.transport.modbus/pom.xml | 37 - .../src/main/feature/feature.xml | 11 - .../transport/modbus/AsyncModbusFailure.java | 65 - .../modbus/AsyncModbusReadResult.java | 93 -- .../modbus/AsyncModbusWriteResult.java | 66 - .../openhab/io/transport/modbus/BitArray.java | 141 --- .../transport/modbus/ModbusBitUtilities.java | 759 ------------ .../modbus/ModbusCommunicationInterface.java | 109 -- .../io/transport/modbus/ModbusConstants.java | 146 --- .../modbus/ModbusFailureCallback.java | 31 - .../io/transport/modbus/ModbusManager.java | 49 - .../transport/modbus/ModbusReadCallback.java | 32 - .../modbus/ModbusReadFunctionCode.java | 25 - .../modbus/ModbusReadRequestBlueprint.java | 132 -- .../transport/modbus/ModbusRegisterArray.java | 113 -- .../io/transport/modbus/ModbusResponse.java | 36 - .../modbus/ModbusResultCallback.java | 24 - .../transport/modbus/ModbusWriteCallback.java | 32 - .../ModbusWriteCoilRequestBlueprint.java | 121 -- .../modbus/ModbusWriteFunctionCode.java | 59 - .../ModbusWriteRegisterRequestBlueprint.java | 108 -- .../modbus/ModbusWriteRequestBlueprint.java | 89 -- .../ModbusWriteRequestBlueprintVisitor.java | 40 - .../openhab/io/transport/modbus/PollTask.java | 34 - .../io/transport/modbus/TaskWithEndpoint.java | 57 - .../io/transport/modbus/ValueBuffer.java | 331 ------ .../io/transport/modbus/WriteTask.java | 32 - .../endpoint/EndpointPoolConfiguration.java | 142 --- .../endpoint/ModbusIPSlaveEndpoint.java | 83 -- .../endpoint/ModbusSerialSlaveEndpoint.java | 107 -- .../modbus/endpoint/ModbusSlaveEndpoint.java | 31 - .../endpoint/ModbusSlaveEndpointVisitor.java | 35 - .../endpoint/ModbusTCPSlaveEndpoint.java | 34 - .../endpoint/ModbusUDPSlaveEndpoint.java | 34 - .../exception/ModbusConnectionException.java | 57 - .../ModbusSlaveErrorResponseException.java | 106 -- .../exception/ModbusSlaveIOException.java | 27 - .../exception/ModbusTransportException.java | 27 - ...expectedResponseFunctionCodeException.java | 48 - ...ModbusUnexpectedResponseSizeException.java | 47 - ...odbusUnexpectedTransactionIdException.java | 56 - .../modbus/internal/AggregateStopWatch.java | 72 -- .../modbus/internal/BasicPollTask.java | 108 -- .../modbus/internal/BasicWriteTask.java | 77 -- .../modbus/internal/ModbusConnectionPool.java | 48 - .../modbus/internal/ModbusLibraryWrapper.java | 347 ------ .../modbus/internal/ModbusManagerImpl.java | 1014 ---------------- .../modbus/internal/ModbusPoolConfig.java | 82 -- .../modbus/internal/ModbusResponseImpl.java | 44 - ...ModbusSlaveErrorResponseExceptionImpl.java | 55 - .../internal/ModbusSlaveIOExceptionImpl.java | 58 - .../modbus/internal/SimpleStopWatch.java | 174 --- .../ModbusSlaveConnectionEvictionPolicy.java | 35 - .../pooling/ModbusSlaveConnectionFactory.java | 28 - .../ModbusSlaveConnectionFactoryImpl.java | 364 ------ .../json/WriteRequestJsonUtilities.java | 217 ---- .../modbus/test/AbstractRequestComparer.java | 70 -- .../modbus/test/BasicBitArrayTest.java | 87 -- .../BitUtilitiesCommandToRegistersTest.java | 331 ------ .../test/BitUtilitiesExtractBitTest.java | 135 --- .../test/BitUtilitiesExtractFloat32Test.java | 80 -- ...UtilitiesExtractIndividualMethodsTest.java | 266 ----- .../test/BitUtilitiesExtractInt8Test.java | 113 -- ...tilitiesExtractStateFromRegistersTest.java | 376 ------ .../test/BitUtilitiesExtractStringTest.java | 136 --- ...UtilitiesTranslateCommand2BooleanTest.java | 79 -- .../io/transport/modbus/test/CoilMatcher.java | 48 - .../modbus/test/IntegrationTestSupport.java | 357 ------ .../test/ModbusSlaveEndpointTestCase.java | 108 -- .../modbus/test/RegisterMatcher.java | 53 - .../transport/modbus/test/ResultCaptor.java | 52 - .../io/transport/modbus/test/SmokeTest.java | 1057 ----------------- .../modbus/test/ValueBufferTest.java | 186 --- .../test/WriteRequestJsonUtilitiesTest.java | 228 ---- bundles/pom.xml | 1 - 115 files changed, 126 insertions(+), 10250 deletions(-) delete mode 100644 bundles/org.openhab.io.transport.modbus/NOTICE delete mode 100644 bundles/org.openhab.io.transport.modbus/README.md delete mode 100644 bundles/org.openhab.io.transport.modbus/pom.xml delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusFailure.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusReadResult.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusWriteResult.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/BitArray.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusBitUtilities.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusCommunicationInterface.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusConstants.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusFailureCallback.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusManager.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadCallback.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadFunctionCode.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadRequestBlueprint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusRegisterArray.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResponse.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResultCallback.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCallback.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCoilRequestBlueprint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteFunctionCode.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRegisterRequestBlueprint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprintVisitor.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/PollTask.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/TaskWithEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ValueBuffer.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/WriteTask.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/EndpointPoolConfiguration.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusIPSlaveEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSerialSlaveEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpointVisitor.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusTCPSlaveEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusUDPSlaveEndpoint.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusConnectionException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveErrorResponseException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveIOException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusTransportException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseFunctionCodeException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseSizeException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedTransactionIdException.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/AggregateStopWatch.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicPollTask.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicWriteTask.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusConnectionPool.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusLibraryWrapper.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusPoolConfig.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusResponseImpl.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveErrorResponseExceptionImpl.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveIOExceptionImpl.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/SimpleStopWatch.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionEvictionPolicy.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactory.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactoryImpl.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/json/WriteRequestJsonUtilities.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/AbstractRequestComparer.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BasicBitArrayTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesCommandToRegistersTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractBitTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractFloat32Test.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractIndividualMethodsTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractInt8Test.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStateFromRegistersTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStringTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesTranslateCommand2BooleanTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/CoilMatcher.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/IntegrationTestSupport.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ModbusSlaveEndpointTestCase.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/RegisterMatcher.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ResultCaptor.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/SmokeTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ValueBufferTest.java delete mode 100644 bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/WriteRequestJsonUtilitiesTest.java diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/DataConverter.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/DataConverter.java index 2f962be621e45..c98f682067f8e 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/DataConverter.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/DataConverter.java @@ -16,8 +16,8 @@ import java.util.BitSet; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ValueBuffer; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ValueBuffer; /** * The {@link DataConverter} Helper class to convert bytes from modbus into desired data format diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/EmergencyBlock.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/EmergencyBlock.java index 7bb27cda316fc..add3f1936f0da 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/EmergencyBlock.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/EmergencyBlock.java @@ -18,9 +18,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.e3dc.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StringType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; /** * The {@link EmergencyBlock} Data object for E3DC Info Block diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/InfoBlock.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/InfoBlock.java index 658049478ae1c..4ba924100ba26 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/InfoBlock.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/InfoBlock.java @@ -14,10 +14,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.e3dc.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.StringType; import org.openhab.core.util.HexUtils; -import org.openhab.io.transport.modbus.ValueBuffer; /** * The {@link InfoBlock} Data object for E3DC Info Block diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/PowerBlock.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/PowerBlock.java index e84eccdf493d1..6660fae6029d0 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/PowerBlock.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/PowerBlock.java @@ -17,9 +17,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.e3dc.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; -import org.openhab.io.transport.modbus.ValueBuffer; /** * The {@link PowerBlock} Data object for E3DC Info Block diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/StringBlock.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/StringBlock.java index 89360daf2703d..a813bdcfab32c 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/StringBlock.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/dto/StringBlock.java @@ -18,9 +18,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.e3dc.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; -import org.openhab.io.transport.modbus.ValueBuffer; /** * The {@link StringBlock} Data object for E3DC Info Block diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCThingHandler.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCThingHandler.java index ba9ec9ced64c1..fd60296c9eb67 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCThingHandler.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCThingHandler.java @@ -30,6 +30,12 @@ import org.openhab.binding.modbus.e3dc.internal.modbus.Parser; import org.openhab.binding.modbus.handler.EndpointNotInitializedException; import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -38,12 +44,6 @@ import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCWallboxThingHandler.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCWallboxThingHandler.java index 7f593e0e47b51..a8ce5720d891f 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCWallboxThingHandler.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCWallboxThingHandler.java @@ -28,6 +28,12 @@ import org.openhab.binding.modbus.e3dc.internal.modbus.Data; import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType; import org.openhab.binding.modbus.e3dc.internal.modbus.Parser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; @@ -37,12 +43,6 @@ import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/modbus/Parser.java b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/modbus/Parser.java index 645f67686f3e3..b643eaa4926af 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/modbus/Parser.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/main/java/org/openhab/binding/modbus/e3dc/internal/modbus/Parser.java @@ -24,8 +24,8 @@ import org.openhab.binding.modbus.e3dc.internal.dto.StringBlock; import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray; import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCHandlerStateTest.java b/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCHandlerStateTest.java index ead7e6787c741..80938a7da251e 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCHandlerStateTest.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/internal/handler/E3DCHandlerStateTest.java @@ -20,6 +20,10 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.openhab.core.config.core.Configuration; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -27,10 +31,6 @@ import org.openhab.core.thing.ThingStatusInfo; import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.ThingHandlerCallback; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; /** * The {@link E3DCHandlerStateTest} Test State handling of Handler if different results occurs diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/util/DataConverterTest.java b/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/util/DataConverterTest.java index bef20dc55cb95..5a7de489d4a85 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/util/DataConverterTest.java +++ b/bundles/org.openhab.binding.modbus.e3dc/src/test/java/org/openhab/binding/modbus/e3dc/util/DataConverterTest.java @@ -19,7 +19,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; import org.openhab.binding.modbus.e3dc.internal.dto.DataConverter; -import org.openhab.io.transport.modbus.ValueBuffer; +import org.openhab.core.io.transport.modbus.ValueBuffer; /** * The {@link DataConverterTest} Test data conversions diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/java/org/openhab/binding/modbus/helioseasycontrols/internal/HeliosEasyControlsHandler.java b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/java/org/openhab/binding/modbus/helioseasycontrols/internal/HeliosEasyControlsHandler.java index ef2170afc0b7c..ca7b67552f359 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/java/org/openhab/binding/modbus/helioseasycontrols/internal/HeliosEasyControlsHandler.java +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/java/org/openhab/binding/modbus/helioseasycontrols/internal/HeliosEasyControlsHandler.java @@ -31,6 +31,13 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; @@ -50,13 +57,6 @@ import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/test/java/org/openhab/binding/modbus/helioseasycontrols/internal/PreparePayloadTest.java b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/test/java/org/openhab/binding/modbus/helioseasycontrols/internal/PreparePayloadTest.java index a3d3d8d80b452..dce80124c9646 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/test/java/org/openhab/binding/modbus/helioseasycontrols/internal/PreparePayloadTest.java +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/test/java/org/openhab/binding/modbus/helioseasycontrols/internal/PreparePayloadTest.java @@ -23,7 +23,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * @author Sami Salonen - Initial contribution diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java index 1e129bd70f1cb..1b86dec889325 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/handler/StiebelEltronHandler.java @@ -33,6 +33,14 @@ import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemInfromationBlockParser; import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemParameterBlockParser; import org.openhab.binding.modbus.stiebeleltron.internal.parser.SystemStateBlockParser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.QuantityType; @@ -47,14 +55,6 @@ import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java index 471226d425103..6614c844cb0fa 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java @@ -15,10 +15,10 @@ import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.library.types.DecimalType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; /** * Base class for parsers with some helper methods diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java index f31028cb79da4..a8d24656ccadd 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/EnergyBlockParser.java @@ -14,7 +14,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.stiebeleltron.internal.dto.EnergyBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses inverter modbus data into an Energy Block diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java index 71b81b70fa0da..3a3e27ee0cf29 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemInfromationBlockParser.java @@ -14,7 +14,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemInformationBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses inverter modbus data into an SystemB Information lock diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java index f1bd72f7c4321..1dcf7cb2fe61d 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemParameterBlockParser.java @@ -14,7 +14,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemParameterBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses inverter modbus data into an System Parameter Block diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java index a49d8388a5aa5..87919558a8eb4 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/SystemStateBlockParser.java @@ -14,7 +14,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.stiebeleltron.internal.dto.SystemStateBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses inverter modbus data into an System State Block diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java index 3e291b702c937..85765ff456505 100644 --- a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java @@ -27,6 +27,14 @@ import org.openhab.binding.modbus.studer.internal.StuderParser.VSMode; import org.openhab.binding.modbus.studer.internal.StuderParser.VTMode; import org.openhab.binding.modbus.studer.internal.StuderParser.VTType; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; @@ -43,14 +51,6 @@ import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.PollTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java index 8627133e3e08b..9f760887016db 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java @@ -30,17 +30,17 @@ import org.openhab.binding.modbus.sunspec.internal.parser.CommonModelParser; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.exception.ModbusSlaveErrorResponseException; import org.openhab.core.library.types.DecimalType; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.exception.ModbusSlaveErrorResponseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/AbstractSunSpecHandler.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/AbstractSunSpecHandler.java index 2f720ba5a7c7e..6212b32c75cc3 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/AbstractSunSpecHandler.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/AbstractSunSpecHandler.java @@ -26,6 +26,12 @@ import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; import org.openhab.binding.modbus.sunspec.internal.SunSpecConfiguration; import org.openhab.binding.modbus.sunspec.internal.dto.ModelBlock; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.PollTask; import org.openhab.core.library.types.QuantityType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; @@ -38,12 +44,6 @@ import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.PollTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/InverterHandler.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/InverterHandler.java index 636c0db98cc10..48cd3bbc03f2d 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/InverterHandler.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/InverterHandler.java @@ -22,10 +22,10 @@ import org.openhab.binding.modbus.sunspec.internal.InverterStatus; import org.openhab.binding.modbus.sunspec.internal.dto.InverterModelBlock; import org.openhab.binding.modbus.sunspec.internal.parser.InverterModelParser; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Thing; import org.openhab.core.types.UnDefType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/MeterHandler.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/MeterHandler.java index 6b212a2ddc475..95e18fe57bf89 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/MeterHandler.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/handler/MeterHandler.java @@ -18,8 +18,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.sunspec.internal.dto.MeterModelBlock; import org.openhab.binding.modbus.sunspec.internal.parser.MeterModelParser; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.thing.Thing; -import org.openhab.io.transport.modbus.ModbusRegisterArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java index 54107ff8a489c..47f6ef9877272 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java @@ -15,10 +15,10 @@ import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.library.types.DecimalType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; /** * Base class for parsers with some helper methods diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/CommonModelParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/CommonModelParser.java index 17d1ddc2f7ad5..95ae7a19b04e6 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/CommonModelParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/CommonModelParser.java @@ -17,8 +17,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.sunspec.internal.SunSpecConstants; import org.openhab.binding.modbus.sunspec.internal.dto.CommonModelBlock; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/InverterModelParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/InverterModelParser.java index 1350b112fb901..286c38c7cac17 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/InverterModelParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/InverterModelParser.java @@ -15,7 +15,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.sunspec.internal.SunSpecConstants; import org.openhab.binding.modbus.sunspec.internal.dto.InverterModelBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parses inverter modbus data into an InverterModelBlock diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/MeterModelParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/MeterModelParser.java index f6adb4a4188d6..ab7d845f734a6 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/MeterModelParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/MeterModelParser.java @@ -15,7 +15,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.modbus.sunspec.internal.SunSpecConstants; import org.openhab.binding.modbus.sunspec.internal.dto.MeterModelBlock; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * Parser for sunspec compatible meters diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/SunspecParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/SunspecParser.java index d678202ab86bb..9fc76dfc8a465 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/SunspecParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/SunspecParser.java @@ -13,7 +13,7 @@ package org.openhab.binding.modbus.sunspec.internal.parser; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; /** * General interface for sunspec parsers diff --git a/bundles/org.openhab.binding.modbus/pom.xml b/bundles/org.openhab.binding.modbus/pom.xml index fcf634894886f..4bd665b67666f 100644 --- a/bundles/org.openhab.binding.modbus/pom.xml +++ b/bundles/org.openhab.binding.modbus/pom.xml @@ -14,13 +14,4 @@ openHAB Add-ons :: Bundles :: Modbus Binding - - - org.openhab.addons.bundles - org.openhab.io.transport.modbus - ${project.version} - provided - - - diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/BaseModbusThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/BaseModbusThingHandler.java index 26544f9bb59d8..4905f5111c880 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/BaseModbusThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/BaseModbusThingHandler.java @@ -18,19 +18,19 @@ import java.util.concurrent.Future; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusFailureCallback; +import org.openhab.core.io.transport.modbus.ModbusReadCallback; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteCallback; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.BridgeHandler; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteCallback; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; /** * This is a convenience class to interact with the Thing's {@link ModbusCommunicationInterface}. diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusEndpointThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusEndpointThingHandler.java index 19a47df4bd2ea..8ecf08d23e7e3 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusEndpointThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusEndpointThingHandler.java @@ -15,8 +15,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.common.registry.Identifiable; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; import org.openhab.core.thing.ThingUID; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; /** * Base interface for thing handlers of endpoint things diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java index 5145103a47012..18810aea171a6 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java @@ -24,6 +24,15 @@ import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal; import org.openhab.binding.modbus.internal.config.ModbusPollerConfiguration; import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusConstants; +import org.openhab.core.io.transport.modbus.ModbusFailureCallback; +import org.openhab.core.io.transport.modbus.ModbusReadCallback; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -33,15 +42,6 @@ import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusConstants; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusBindingConstantsInternal.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusBindingConstantsInternal.java index 4d8d4fe85a7a7..10792ac5dee61 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusBindingConstantsInternal.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusBindingConstantsInternal.java @@ -18,8 +18,8 @@ import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; import org.openhab.core.thing.ThingTypeUID; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; /** * The {@link ModbusBinding} class defines common constants, which are diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusHandlerFactory.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusHandlerFactory.java index 76ccba0c85530..67f58597ea461 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusHandlerFactory.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/ModbusHandlerFactory.java @@ -23,13 +23,13 @@ import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler; import org.openhab.binding.modbus.internal.handler.ModbusSerialThingHandler; import org.openhab.binding.modbus.internal.handler.ModbusTcpThingHandler; +import org.openhab.core.io.transport.modbus.ModbusManager; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.openhab.io.transport.modbus.ModbusManager; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/AbstractModbusEndpointThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/AbstractModbusEndpointThingHandler.java index d38f74a73e534..acfb9f217fc1c 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/AbstractModbusEndpointThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/AbstractModbusEndpointThingHandler.java @@ -17,16 +17,16 @@ import org.openhab.binding.modbus.handler.EndpointNotInitializedException; import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; import org.openhab.binding.modbus.internal.ModbusConfigurationException; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusManager; +import org.openhab.core.io.transport.modbus.endpoint.EndpointPoolConfiguration; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusManager; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java index fbda70afd5d05..0bd69bb776fd1 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java @@ -31,6 +31,23 @@ import org.openhab.binding.modbus.internal.ModbusConfigurationException; import org.openhab.binding.modbus.internal.Transformation; import org.openhab.binding.modbus.internal.config.ModbusDataConfiguration; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.AsyncModbusWriteResult; +import org.openhab.core.io.transport.modbus.BitArray; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusConstants; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusWriteCoilRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.exception.ModbusConnectionException; +import org.openhab.core.io.transport.modbus.exception.ModbusTransportException; +import org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities; import org.openhab.core.library.items.ContactItem; import org.openhab.core.library.items.DateTimeItem; import org.openhab.core.library.items.DimmerItem; @@ -55,23 +72,6 @@ import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.AsyncModbusWriteResult; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusConstants; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.exception.ModbusConnectionException; -import org.openhab.io.transport.modbus.exception.ModbusTransportException; -import org.openhab.io.transport.modbus.json.WriteRequestJsonUtilities; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusSerialThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusSerialThingHandler.java index 8df069ce29ad4..683a20a99ce92 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusSerialThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusSerialThingHandler.java @@ -21,12 +21,12 @@ import org.openhab.binding.modbus.handler.EndpointNotInitializedException; import org.openhab.binding.modbus.internal.ModbusConfigurationException; import org.openhab.binding.modbus.internal.config.ModbusSerialConfiguration; +import org.openhab.core.io.transport.modbus.ModbusManager; +import org.openhab.core.io.transport.modbus.endpoint.EndpointPoolConfiguration; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.ThingHandlerService; -import org.openhab.io.transport.modbus.ModbusManager; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; /** * Endpoint thing handler for serial slaves diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusTcpThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusTcpThingHandler.java index 4d0b66576a0ba..87fbc4864fdea 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusTcpThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusTcpThingHandler.java @@ -21,12 +21,12 @@ import org.openhab.binding.modbus.handler.EndpointNotInitializedException; import org.openhab.binding.modbus.internal.ModbusConfigurationException; import org.openhab.binding.modbus.internal.config.ModbusTcpConfiguration; +import org.openhab.core.io.transport.modbus.ModbusManager; +import org.openhab.core.io.transport.modbus.endpoint.EndpointPoolConfiguration; +import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.ThingHandlerService; -import org.openhab.io.transport.modbus.ModbusManager; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; /** * Endpoint thing handler for TCP slaves diff --git a/bundles/org.openhab.io.transport.modbus/NOTICE b/bundles/org.openhab.io.transport.modbus/NOTICE deleted file mode 100644 index 0ca708bef198a..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/NOTICE +++ /dev/null @@ -1,20 +0,0 @@ -This content is produced and maintained by the openHAB project. - -* Project home: https://www.openhab.org - -== Declared Project Licenses - -This program and the accompanying materials are made available under the terms -of the Eclipse Public License 2.0 which is available at -https://www.eclipse.org/legal/epl-2.0/. - -== Source Code - -https://github.com/openhab/openhab-addons - -== Third-party Content - -jsoup -* License: MIT License -* Project: https://jsoup.org/ -* Source: https://github.com/jhy/jsoup diff --git a/bundles/org.openhab.io.transport.modbus/README.md b/bundles/org.openhab.io.transport.modbus/README.md deleted file mode 100644 index 9fa7bbebf6d91..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Modbus Transport - -This transport provides a nice abstraction for modbus. diff --git a/bundles/org.openhab.io.transport.modbus/pom.xml b/bundles/org.openhab.io.transport.modbus/pom.xml deleted file mode 100644 index c64d95c274783..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - - org.openhab.addons.bundles - org.openhab.addons.reactor.bundles - 3.0.0-SNAPSHOT - - - org.openhab.io.transport.modbus - - openHAB Add-ons :: Bundles :: IO :: Modbus Transport - - - gnu.io;version="[3.12,6)" - commons-pool2 - - - - - org.apache.commons - commons-pool2 - 2.8.1 - compile - - - net.wimpi - jamod - 1.2.4.OH - compile - - - - diff --git a/bundles/org.openhab.io.transport.modbus/src/main/feature/feature.xml b/bundles/org.openhab.io.transport.modbus/src/main/feature/feature.xml deleted file mode 100644 index db8b4406e1644..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/feature/feature.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features - - - openhab-runtime-base - openhab-transport-serial - mvn:org.apache.commons/commons-pool2/2.8.1 - mvn:org.openhab.addons.bundles/org.openhab.io.transport.modbus/${project.version} - - diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusFailure.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusFailure.java deleted file mode 100644 index 09917e87b25ec..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusFailure.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.Objects; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Encapsulates result of modbus read operations - * - * @author Nagy Attila Gabor - Initial contribution - */ -@NonNullByDefault -public class AsyncModbusFailure { - private final R request; - - private final Exception cause; - - public AsyncModbusFailure(R request, Exception cause) { - Objects.requireNonNull(request, "Request must not be null!"); - Objects.requireNonNull(cause, "Cause must not be null!"); - this.request = request; - this.cause = cause; - } - - /** - * Get request matching this response - * - * @return request object - */ - public R getRequest() { - return request; - } - - /** - * Get cause of error - * - * @return exception representing error - */ - public Exception getCause() { - return cause; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("AsyncModbusReadResult("); - builder.append("request = "); - builder.append(request); - builder.append(", error = "); - builder.append(cause); - builder.append(")"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusReadResult.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusReadResult.java deleted file mode 100644 index 0d02b11de6798..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusReadResult.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.Objects; -import java.util.Optional; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Encapsulates result of modbus read operations - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class AsyncModbusReadResult { - - private final ModbusReadRequestBlueprint request; - - private final Optional bits; - - private final Optional registers; - - public AsyncModbusReadResult(ModbusReadRequestBlueprint request, ModbusRegisterArray registers) { - Objects.requireNonNull(request, "Request must not be null!"); - Objects.requireNonNull(registers, "Registers must not be null!"); - this.request = request; - this.registers = Optional.of(registers); - this.bits = Optional.empty(); - } - - public AsyncModbusReadResult(ModbusReadRequestBlueprint request, BitArray bits) { - Objects.requireNonNull(request, "Request must not be null!"); - Objects.requireNonNull(bits, "Bits must not be null!"); - this.request = request; - this.registers = Optional.empty(); - this.bits = Optional.of(bits); - } - - /** - * Get request matching this response - * - * @return request object - */ - public ModbusReadRequestBlueprint getRequest() { - return request; - } - - /** - * Get "coil" or "discrete input" bit data in the case of no errors - * - * @return bit data - */ - public Optional getBits() { - return bits; - } - - /** - * Get "input register" or "holding register" data in the case of no errors - * - * @return register data - */ - public Optional getRegisters() { - return registers; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("AsyncModbusReadResult("); - builder.append("request = "); - builder.append(request); - bits.ifPresent(bits -> { - builder.append(", bits = "); - builder.append(bits); - }); - registers.ifPresent(registers -> { - builder.append(", registers = "); - builder.append(registers); - }); - builder.append(")"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusWriteResult.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusWriteResult.java deleted file mode 100644 index b5b3a4eda55ff..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusWriteResult.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.Objects; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Encapsulates result of modbus write operations - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class AsyncModbusWriteResult { - - private final ModbusWriteRequestBlueprint request; - - private final ModbusResponse response; - - public AsyncModbusWriteResult(ModbusWriteRequestBlueprint request, ModbusResponse response) { - Objects.requireNonNull(request, "Request must not be null!"); - Objects.requireNonNull(response, "Response must not be null!"); - this.request = request; - this.response = response; - } - - /** - * Get request matching this response - * - * @return request object - */ - public ModbusWriteRequestBlueprint getRequest() { - return request; - } - - /** - * Get response - * - * @return response - */ - public ModbusResponse getResponse() { - return response; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("AsyncModbusWriteResult("); - builder.append("request = "); - builder.append(request); - builder.append(", response = "); - builder.append(response); - builder.append(")"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/BitArray.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/BitArray.java deleted file mode 100644 index 6b73eceb390f8..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/BitArray.java +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.BitSet; -import java.util.Iterator; -import java.util.stream.IntStream; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Class that implements a collection for - * bits - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class BitArray implements Iterable { - - private final BitSet wrapped; - private final int length; - - public BitArray(int nbits) { - this(new BitSet(nbits), nbits); - } - - public BitArray(boolean... bits) { - this(bitSetFromBooleans(bits), bits.length); - } - - public BitArray(BitSet wrapped, int length) { - this.wrapped = wrapped; - this.length = length; - } - - private static BitSet bitSetFromBooleans(boolean... bits) { - BitSet bitSet = new BitSet(bits.length); - for (int i = 0; i < bits.length; i++) { - bitSet.set(i, bits[i]); - } - - return bitSet; - } - - private boolean sizeAndValuesEquals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!(obj instanceof BitArray)) { - return false; - } - BitArray other = (BitArray) obj; - if (this.size() != other.size()) { - return false; - } - for (int i = 0; i < this.size(); i++) { - if (this.getBit(i) != other.getBit(i)) { - return false; - } - } - return true; - } - - /** - * Returns the state of the bit at the given index - * - * Index 0 matches LSB (rightmost) bit - *

- * - * @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 boolean getBit(int index) { - if (index >= size()) { - throw new IndexOutOfBoundsException(); - } - return this.wrapped.get(index); - } - - public void setBit(int index, boolean value) { - if (value) { - this.wrapped.set(index); - } else { - this.wrapped.clear(index); - } - } - - /** - * Get number of bits stored in this instance - * - * @return - */ - public int size() { - return length; - } - - @Override - public String toString() { - return new StringBuilder("BitArray(bits=").append(length == 0 ? "" : toBinaryString()).append(")") - .toString(); - } - - @Override - public Iterator iterator() { - return IntStream.range(0, size()).mapToObj(i -> getBit(i)).iterator(); - } - - @Override - public boolean equals(@Nullable Object obj) { - return sizeAndValuesEquals(obj); - } - - /** - * Get data as binary string - * - * For example, 0010 - * - * @return string representing the data - */ - public String toBinaryString() { - final StringBuilder buffer = new StringBuilder(size()); - IntStream.range(0, size()).mapToObj(i -> getBit(i) ? '1' : '0').forEach(buffer::append); - return buffer.toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusBitUtilities.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusBitUtilities.java deleted file mode 100644 index b55c4eeb7e586..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusBitUtilities.java +++ /dev/null @@ -1,759 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.nio.charset.Charset; -import java.util.Optional; - -import org.apache.commons.lang.NotImplementedException; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; - -/** - * Utilities for working with binary data. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ModbusBitUtilities { - - /** - * Read data from registers and convert the result to DecimalType - * Interpretation of index goes as follows depending on type - * - * BIT: - * - a single bit is read from the registers - * - indices between 0...15 (inclusive) represent bits of the first register - * - indices between 16...31 (inclusive) represent bits of the second register, etc. - * - index 0 refers to the least significant bit of the first register - * - index 1 refers to the second least significant bit of the first register, etc. - * INT8: - * - a byte (8 bits) from the registers is interpreted as signed integer - * - index 0 refers to low byte of the first register, 1 high byte of first register - * - index 2 refers to low byte of the second register, 3 high byte of second register, etc. - * - it is assumed that each high and low byte is encoded in most significant bit first order - * UINT8: - * - same as INT8 except value is interpreted as unsigned integer - * INT16: - * - register with index (counting from zero) is interpreted as 16 bit signed integer. - * - it is assumed that each register is encoded in most significant bit first order - * UINT16: - * - same as INT16 except value is interpreted as unsigned integer - * INT32: - * - registers (index) and (index + 1) are interpreted as signed 32bit integer. - * - it assumed that the first register contains the most significant 16 bits - * - it is assumed that each register is encoded in most significant bit first order - * INT32_SWAP: - * - Same as INT32 but registers swapped - * UINT32: - * - same as INT32 except value is interpreted as unsigned integer - * UINT32_SWAP: - * - same as INT32_SWAP except value is interpreted as unsigned integer - * FLOAT32: - * - registers (index) and (index + 1) are interpreted as signed 32bit floating point number. - * - it assumed that the first register contains the most significant 16 bits - * - it is assumed that each register is encoded in most significant bit first order - * - floating point NaN and infinity will return as empty optional - * FLOAT32_SWAP: - * - Same as FLOAT32 but registers swapped - * INT64: - * - registers (index), (index + 1), (index + 2), (index + 3) are interpreted as signed 64bit integer. - * - it assumed that the first register contains the most significant 16 bits - * - it is assumed that each register is encoded in most significant bit first order - * INT64_SWAP: - * - same as INT64 but registers swapped, that is, registers (index + 3), (index + 2), (index + 1), (index + 1) are - * interpreted as signed 64bit integer - * UINT64: - * - same as INT64 except value is interpreted as unsigned integer - * UINT64_SWAP: - * - same as INT64_SWAP except value is interpreted as unsigned integer - * - * @param registers list of registers, each register represent 16bit of data - * @param index zero based item index. Interpretation of this depends on type, see examples above. - * With type larger or equal to 16 bits, the index tells the register index to start reading - * from. - * With type less than 16 bits, the index tells the N'th item to read from the registers. - * @param type item type, e.g. unsigned 16bit integer (ModbusBindingProvider.ValueType.UINT16) - * @return number representation queried value, DecimalType. Empty optional is returned - * with NaN and infinity floating point values - * @throws NotImplementedException in cases where implementation is lacking for the type. This can be considered a - * bug - * @throws IllegalArgumentException when index is out of bounds of registers - * - */ - public static Optional extractStateFromRegisters(ModbusRegisterArray registers, int index, - ModbusConstants.ValueType type) { - byte[] bytes = registers.getBytes(); - switch (type) { - case BIT: - return Optional.of(new DecimalType(extractBit(bytes, index))); - case INT8: { - int registerIndex = index / 2; - boolean hiByte = index % 2 == 1; - return Optional.of(new DecimalType(extractSInt8(bytes, registerIndex, hiByte))); - } - case UINT8: { - int registerIndex = index / 2; - boolean hiByte = index % 2 == 1; - return Optional.of(new DecimalType(extractUInt8(bytes, registerIndex, hiByte))); - } - case INT16: - return Optional.of(new DecimalType(extractSInt16(bytes, index * 2))); - case UINT16: - return Optional.of(new DecimalType(extractUInt16(bytes, index * 2))); - case INT32: - return Optional.of(new DecimalType(extractSInt32(bytes, index * 2))); - case UINT32: - return Optional.of(new DecimalType(extractUInt32(bytes, index * 2))); - case FLOAT32: - try { - return Optional.of(new DecimalType(extractFloat32(bytes, index * 2))); - } catch (NumberFormatException e) { - // floating point NaN or infinity encountered - return Optional.empty(); - } - case INT64: - return Optional.of(new DecimalType(extractSInt64(bytes, index * 2))); - case UINT64: - return Optional.of(new DecimalType(new BigDecimal(extractUInt64(bytes, index * 2)))); - case INT32_SWAP: - return Optional.of(new DecimalType(extractSInt32Swap(bytes, index * 2))); - case UINT32_SWAP: - return Optional.of(new DecimalType(extractUInt32Swap(bytes, index * 2))); - case FLOAT32_SWAP: - try { - return Optional.of(new DecimalType(extractFloat32Swap(bytes, index * 2))); - } catch (NumberFormatException e) { - // floating point NaN or infinity encountered - return Optional.empty(); - } - case INT64_SWAP: - return Optional.of(new DecimalType(extractSInt64Swap(bytes, index * 2))); - case UINT64_SWAP: - return Optional.of(new DecimalType(new BigDecimal(extractUInt64Swap(bytes, index * 2)))); - default: - throw new IllegalArgumentException(type.getConfigValue()); - } - } - - private static void assertIndexAndType(byte[] bytes, int index, ValueType type) { - int typeBits = type.getBits(); - // for 8-bit types and larger, index specifies the index of the byte. For bits, index specifies the index of the - // bit (of the whole data) - int indexPositionAsBitIndex = Math.min(type.getBits(), 8) * index; - int endBitIndex = indexPositionAsBitIndex + typeBits - 1; - int lastValidIndex = bytes.length * 8 - 1; - if (endBitIndex > lastValidIndex || index < 0) { - throw new IllegalArgumentException( - String.format("Index=%d with type=%s is out-of-bounds given registers of size %d ", index, type, - bytes.length / 2)); - } - } - - /** - * Extract single bit from registers represented by sequence of bytes - * - * - indices between 0...15 (inclusive) represent bits of the first register - * - indices between 16...31 (inclusive) represent bits of the second register, etc. - * - index 0 refers to the least significant bit of the first register - * - index 1 refers to the second least significant bit of the first register, etc. - * - * @param bytes registers represented by sequence of bytes - * @param index index of bit - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when index is out of bounds - */ - public static int extractBit(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.BIT); - int registerIndex = index / 16; - int bitIndexWithinRegister = index % 16; - return extractBit(bytes, registerIndex, bitIndexWithinRegister); - } - - /** - * Extract single bit from registers represented by sequence of bytes - * - * bitIndexWithinRegister between 0...15 (inclusive) represent bits of the first register, where 0 refers to the - * least significant bit of the register, index 1 refers to the second least significant bit of the register, etc. - * - * @param bytes registers represented by sequence of bytes - * @param registerIndex index of register. First register has index of 0. - * @param bitIndexWithinRegister bit index within the register - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when registerIndex and/or bitIndexWithinRegister is out of bounds - */ - public static int extractBit(byte[] bytes, int registerIndex, int bitIndexWithinRegister) { - if (bitIndexWithinRegister < 0 || bitIndexWithinRegister > 15) { - throw new IllegalArgumentException( - String.format("bitIndexWithinRegister=%d is out-of-bounds (max 15)", bitIndexWithinRegister)); - } else if (registerIndex < 0) { - throw new IllegalArgumentException( - String.format("registerIndex=%d is out-of-bounds", bitIndexWithinRegister)); - } - boolean hiByte = bitIndexWithinRegister >= 8; - int indexWithinByte = bitIndexWithinRegister % 8; - int byteIndex = 2 * registerIndex + (hiByte ? 0 : 1); - if (byteIndex >= bytes.length) { - throw new IllegalArgumentException(String.format( - "registerIndex=%d, bitIndexWithinRegister=%d is out-of-bounds with registers of size %d", - registerIndex, bitIndexWithinRegister, bytes.length / 2)); - } - return ((bytes[byteIndex] >>> indexWithinByte) & 1); - } - - /** - * Extract signed 8-bit integer (byte) from registers represented by sequence of bytes - * - * @param bytes registers represented by sequence of bytes - * @param registerIndex index of register. First register has index of 0. - * @param hiByte whether to extract hi byte or lo byte - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when index is out of bounds - */ - public static byte extractSInt8(byte[] bytes, int registerIndex, boolean hiByte) { - int byteIndex = 2 * registerIndex + (hiByte ? 0 : 1); - byte signed = extractSInt8(bytes, byteIndex); - return signed; - } - - /** - * Extract signed 8-bit integer (byte) from registers represented by sequence of bytes - * - * - index 0 refers to low byte of the first register, 1 high byte of first register - * - index 2 refers to low byte of the second register, 3 high byte of second register, etc. - * - it is assumed that each high and low byte is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param registerIndex index of register. First register has index of 0. - * @param index index of the byte in registers - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when index is out of bounds - */ - public static byte extractSInt8(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT8); - byte signed = bytes[index]; - return signed; - } - - /** - * Extract unsigned 8-bit integer (byte) from registers represented by sequence of bytes - * - * @param bytes registers represented by sequence of bytes - * @param registerIndex index of register. First register has index of 0. - * @param hiByte whether to extract hi byte or lo byte - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when registerIndex is out of bounds - */ - public static short extractUInt8(byte[] bytes, int registerIndex, boolean hiByte) { - int byteIndex = 2 * registerIndex + (hiByte ? 0 : 1); - short unsigned = extractUInt8(bytes, byteIndex); - return unsigned; - } - - /** - * Extract unsigned 8-bit integer (byte) from registers represented by sequence of bytes - * - * - index 0 refers to low byte of the first register, 1 high byte of first register - * - index 2 refers to low byte of the second register, 3 high byte of second register, etc. - * - it is assumed that each high and low byte is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param registerIndex index of register. First register has index of 0. - * @param index index of the byte in registers - * @return 0 when bit is set, 1 otherwise - * @throws IllegalArgumentException when index is out of bounds - */ - public static short extractUInt8(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT8); - int signed = extractSInt8(bytes, index); - short unsigned = (short) (signed & 0xff); - assert unsigned >= 0; - return unsigned; - } - - /** - * Extract signed 16-bit integer (short) from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param index index of register. First register has index of 0. - * @return register with index interpreted as 16 bit signed integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static short extractSInt16(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT16); - int hi = (bytes[index] & 0xff); - int lo = (bytes[index + 1] & 0xff); - short signed = (short) ((hi << 8) | lo); - return signed; - } - - /** - * Extract unsigned 16-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param index index of register. First register has index of 0. - * @return register with index interpreted as 16 bit unsigned integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static int extractUInt16(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT16); - int signed = extractSInt16(bytes, index); - int unsigned = signed & 0xffff; - assert unsigned >= 0; - return unsigned; - } - - /** - * Extract signed 32-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index) and (index+1) interpreted as 32 bit signed integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static int extractSInt32(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT32); - int hi1 = bytes[index + 0] & 0xff; - int lo1 = bytes[index + 1] & 0xff; - int hi2 = bytes[index + 2] & 0xff; - int lo2 = bytes[index + 3] & 0xff; - int signed = (hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2; - return signed; - } - - /** - * Extract unsigned 32-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index) and (index+1) interpreted as 32 bit unsigned integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static long extractUInt32(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT32); - long signed = extractSInt32(bytes, index); - long unsigned = signed & 0xffff_ffffL; - assert unsigned >= 0; - return unsigned; - } - - /** - * Extract signed 32-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * This is identical with extractSInt32, but with registers swapped. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index+1), (index) interpreted as 32 bit signed integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static int extractSInt32Swap(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT32_SWAP); - // swapped order of registers, high 16 bits *follow* low 16 bits - int hi1 = bytes[index + 2] & 0xff; - int lo1 = bytes[index + 3] & 0xff; - int hi2 = bytes[index + 0] & 0xff; - int lo2 = bytes[index + 1] & 0xff; - int signed = (hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2; - return signed; - } - - /** - * Extract unsigned 32-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * This is identical with extractUInt32, but with registers swapped. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index+1), (index) interpreted as 32 bit unsigned integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static long extractUInt32Swap(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT32_SWAP); - long signed = extractSInt32Swap(bytes, index); - long unsigned = signed & 0xffff_ffffL; - assert unsigned >= 0; - return unsigned; - } - - /** - * Extract signed 64-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index), (index+1), (index+2), (index+3) interpreted as 64 bit signed integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static long extractSInt64(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT64); - byte hi1 = (byte) (bytes[index + 0] & 0xff); - byte lo1 = (byte) (bytes[index + 1] & 0xff); - byte hi2 = (byte) (bytes[index + 2] & 0xff); - byte lo2 = (byte) (bytes[index + 3] & 0xff); - byte hi3 = (byte) (bytes[index + 4] & 0xff); - byte lo3 = (byte) (bytes[index + 5] & 0xff); - byte hi4 = (byte) (bytes[index + 6] & 0xff); - byte lo4 = (byte) (bytes[index + 7] & 0xff); - return new BigInteger(new byte[] { hi1, lo1, hi2, lo2, hi3, lo3, hi4, lo4 }).longValue(); - } - - /** - * Extract unsigned 64-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index), (index+1), (index+2), (index+3) interpreted as 64 bit unsigned integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static BigInteger extractUInt64(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT64); - byte hi1 = (byte) (bytes[index + 0] & 0xff); - byte lo1 = (byte) (bytes[index + 1] & 0xff); - byte hi2 = (byte) (bytes[index + 2] & 0xff); - byte lo2 = (byte) (bytes[index + 3] & 0xff); - byte hi3 = (byte) (bytes[index + 4] & 0xff); - byte lo3 = (byte) (bytes[index + 5] & 0xff); - byte hi4 = (byte) (bytes[index + 6] & 0xff); - byte lo4 = (byte) (bytes[index + 7] & 0xff); - return new BigInteger(1, new byte[] { hi1, lo1, hi2, lo2, hi3, lo3, hi4, lo4 }); - } - - /** - * Extract signed 64-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * This is identical with extractInt64, but with registers swapped (registers with higher index before lower index). - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index+3), (index+2), (index+1), (index) interpreted as 64 bit signed integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static long extractSInt64Swap(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.INT64_SWAP); - // Swapped order of registers - byte hi1 = (byte) (bytes[index + 6] & 0xff); - byte lo1 = (byte) (bytes[index + 7] & 0xff); - byte hi2 = (byte) (bytes[index + 4] & 0xff); - byte lo2 = (byte) (bytes[index + 5] & 0xff); - byte hi3 = (byte) (bytes[index + 2] & 0xff); - byte lo3 = (byte) (bytes[index + 3] & 0xff); - byte hi4 = (byte) (bytes[index + 0] & 0xff); - byte lo4 = (byte) (bytes[index + 1] & 0xff); - return new BigInteger(new byte[] { hi1, lo1, hi2, lo2, hi3, lo3, hi4, lo4 }).longValue(); - } - - /** - * Extract unsigned 64-bit integer from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * This is identical with extractUInt64, but with registers swapped (registers with higher index before lower - * index). - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index+3), (index+2), (index+1), (index) interpreted as 64 bit unsigned integer - * @throws IllegalArgumentException when index is out of bounds - */ - public static BigInteger extractUInt64Swap(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.UINT64_SWAP); - // Swapped order of registers - byte hi1 = (byte) (bytes[index + 6] & 0xff); - byte lo1 = (byte) (bytes[index + 7] & 0xff); - byte hi2 = (byte) (bytes[index + 4] & 0xff); - byte lo2 = (byte) (bytes[index + 5] & 0xff); - byte hi3 = (byte) (bytes[index + 2] & 0xff); - byte lo3 = (byte) (bytes[index + 3] & 0xff); - byte hi4 = (byte) (bytes[index + 0] & 0xff); - byte lo4 = (byte) (bytes[index + 1] & 0xff); - return new BigInteger(1, new byte[] { hi1, lo1, hi2, lo2, hi3, lo3, hi4, lo4 }); - } - - /** - * Extract single-precision 32-bit IEEE 754 floating point from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * Note that this method can return floating point NaN and floating point infinity. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index), (index+1), (index+2), (index+3) interpreted as single-precision 32-bit IEEE 754 - * floating point - * @throws IllegalArgumentException when index is out of bounds - */ - public static float extractFloat32(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.FLOAT32); - int hi1 = bytes[index + 0] & 0xff; - int lo1 = bytes[index + 1] & 0xff; - int hi2 = bytes[index + 2] & 0xff; - int lo2 = bytes[index + 3] & 0xff; - int bits32 = (hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2; - return Float.intBitsToFloat(bits32); - } - - /** - * Extract single-precision 32-bit IEEE 754 floating point from registers represented by sequence of bytes - * - * It is assumed that each register is encoded in most significant bit first order. - * - * This is identical with extractFloat32, but with registers swapped (registers with higher index before lower - * index). - * - * Note that this method can return floating point NaN and floating point infinity. - * - * @param bytes registers represented by sequence of bytes - * @param index index of first register. First register has index of 0. - * @return registers (index+3), (index+2), (index+1), (index) interpreted as single-precision 32-bit IEEE 754 - * floating point - * @throws IllegalArgumentException when index is out of bounds - */ - public static float extractFloat32Swap(byte[] bytes, int index) { - assertIndexAndType(bytes, index, ValueType.FLOAT32_SWAP); - // swapped order of registers, high 16 bits *follow* low 16 bits - int hi1 = bytes[index + 2] & 0xff; - int lo1 = bytes[index + 3] & 0xff; - int hi2 = bytes[index + 0] & 0xff; - int lo2 = bytes[index + 1] & 0xff; - int bits32 = (hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2; - return Float.intBitsToFloat(bits32); - } - - /** - * Read data from registers and convert the result to String - * Strings should start the the first byte of a register, but could - * have an odd number of characters. - * Raw byte array values are converted using the charset parameter - * and a maximum of length bytes are read. However reading stops at the first - * NUL byte encountered. - * - * Registers are read in big-endian order, i.e. two registers consisting 4 bytes (ab, cd) are parsed as sequence of - * bytes (a,b,c,d). - * - * @param registers list of registers, each register represent 16bit of data - * @param registerIndex zero based register index. Registers are handled as 16bit registers, - * this parameter defines the starting register. - * @param length maximum length of string in 8bit characters (number of bytes considered) - * @param charset the character set used to construct the string. - * @return string representation queried value - * @throws IllegalArgumentException when index is out of bounds of registers - */ - public static String extractStringFromRegisters(ModbusRegisterArray registers, int registerIndex, int length, - Charset charset) { - return extractStringFromBytes(registers.getBytes(), registerIndex * 2, length, charset); - } - - /** - * Read data from bytes and convert the result to String - * - * Raw byte array values are converted using the charset parameter - * and a maximum of length bytes are read. However reading stops at the first - * NUL byte encountered. - * - * @param bytes bytes representing the registers - * @param byteIndex zero based byte index - * @param length maximum length of string in 8bit characters (number of bytes considered) - * @param charset the character set used to construct the string. - * @return string representation queried value - * @throws IllegalArgumentException when index is out of bounds of registers - */ - public static String extractStringFromBytes(byte[] bytes, int byteIndex, int length, Charset charset) { - if (byteIndex + length > bytes.length) { - throw new IllegalArgumentException( - String.format("byteIndex=%d with length=%d is out-of-bounds given registers of size %d", byteIndex, - length, bytes.length)); - } - if (byteIndex < 0) { - throw new IllegalArgumentException("Negative index values are not supported"); - } - if (length < 0) { - throw new IllegalArgumentException("Negative string length is not supported"); - } - - int effectiveLength = length; - - // Find first zero byte in registers and call reduce length such that we stop before it - for (int i = 0; i < length; i++) { - if (bytes[byteIndex + i] == '\0') { - effectiveLength = i; - break; - } - } - - return new String(bytes, byteIndex, effectiveLength, charset); - } - - /** - * Convert command to array of registers using a specific value type - * - * @param command command to be converted - * @param type value type to use in conversion - * @return array of registers - * @throws NotImplementedException in cases where implementation is lacking for the type. This is thrown with 1-bit - * and 8-bit value types - */ - public static ModbusRegisterArray commandToRegisters(Command command, ModbusConstants.ValueType type) { - DecimalType numericCommand; - if (command instanceof OnOffType || command instanceof OpenClosedType) { - numericCommand = translateCommand2Boolean(command).get() ? new DecimalType(BigDecimal.ONE) - : DecimalType.ZERO; - } else if (command instanceof DecimalType) { - numericCommand = (DecimalType) command; - } else { - throw new NotImplementedException(String.format( - "Command '%s' of class '%s' cannot be converted to registers. Please use OnOffType, OpenClosedType, or DecimalType commands.", - command, command.getClass().getName())); - } - if (type.getBits() != 16 && type.getBits() != 32 && type.getBits() != 64) { - throw new IllegalArgumentException(String.format( - "Illegal type=%s (bits=%d). Only 16bit and 32bit types are supported", type, type.getBits())); - } - switch (type) { - case INT16: - case UINT16: { - short shortValue = numericCommand.shortValue(); - // big endian byte ordering - byte hi = (byte) (shortValue >> 8); - byte lo = (byte) shortValue; - return new ModbusRegisterArray(new byte[] { hi, lo }); - } - case INT32: - case UINT32: { - int intValue = numericCommand.intValue(); - // big endian byte ordering - byte hi1 = (byte) (intValue >> 24); - byte lo1 = (byte) (intValue >> 16); - byte hi2 = (byte) (intValue >> 8); - byte lo2 = (byte) intValue; - return new ModbusRegisterArray(new byte[] { hi1, lo1, hi2, lo2 }); - } - case INT32_SWAP: - case UINT32_SWAP: { - int intValue = numericCommand.intValue(); - // big endian byte ordering - byte hi1 = (byte) (intValue >> 24); - byte lo1 = (byte) (intValue >> 16); - byte hi2 = (byte) (intValue >> 8); - byte lo2 = (byte) intValue; - // Swapped order of registers - return new ModbusRegisterArray(new byte[] { hi2, lo2, hi1, lo1 }); - } - case FLOAT32: { - float floatValue = numericCommand.floatValue(); - int intBits = Float.floatToIntBits(floatValue); - // big endian byte ordering - byte hi1 = (byte) (intBits >> 24); - byte lo1 = (byte) (intBits >> 16); - byte hi2 = (byte) (intBits >> 8); - byte lo2 = (byte) intBits; - return new ModbusRegisterArray(new byte[] { hi1, lo1, hi2, lo2 }); - } - case FLOAT32_SWAP: { - float floatValue = numericCommand.floatValue(); - int intBits = Float.floatToIntBits(floatValue); - // big endian byte ordering - byte hi1 = (byte) (intBits >> 24); - byte lo1 = (byte) (intBits >> 16); - byte hi2 = (byte) (intBits >> 8); - byte lo2 = (byte) intBits; - // Swapped order of registers - return new ModbusRegisterArray(new byte[] { hi2, lo2, hi1, lo1 }); - } - case INT64: - case UINT64: { - long longValue = numericCommand.longValue(); - // big endian byte ordering - byte hi1 = (byte) (longValue >> 56); - byte lo1 = (byte) (longValue >> 48); - byte hi2 = (byte) (longValue >> 40); - byte lo2 = (byte) (longValue >> 32); - byte hi3 = (byte) (longValue >> 24); - byte lo3 = (byte) (longValue >> 16); - byte hi4 = (byte) (longValue >> 8); - byte lo4 = (byte) longValue; - return new ModbusRegisterArray(new byte[] { hi1, lo1, hi2, lo2, hi3, lo3, hi4, lo4 }); - } - case INT64_SWAP: - case UINT64_SWAP: { - long longValue = numericCommand.longValue(); - // big endian byte ordering - byte hi1 = (byte) (longValue >> 56); - byte lo1 = (byte) (longValue >> 48); - byte hi2 = (byte) (longValue >> 40); - byte lo2 = (byte) (longValue >> 32); - byte hi3 = (byte) (longValue >> 24); - byte lo3 = (byte) (longValue >> 16); - byte hi4 = (byte) (longValue >> 8); - byte lo4 = (byte) longValue; - // Swapped order of registers - return new ModbusRegisterArray(new byte[] { hi4, lo4, hi3, lo3, hi2, lo2, hi1, lo1 }); - } - default: - throw new NotImplementedException( - String.format("Illegal type=%s. Missing implementation for this type", type)); - } - } - - /** - * Converts command to a boolean - * - * true value is represented by {@link OnOffType.ON}, {@link OpenClosedType.OPEN}. - * false value is represented by {@link OnOffType.OFF}, {@link OpenClosedType.CLOSED}. - * Furthermore, {@link DecimalType} are converted to boolean true if they are unequal to zero. - * - * @param command to convert to boolean - * @return Boolean value matching the command. Empty if command cannot be converted - */ - public static Optional translateCommand2Boolean(Command command) { - if (command.equals(OnOffType.ON)) { - return Optional.of(Boolean.TRUE); - } - if (command.equals(OnOffType.OFF)) { - return Optional.of(Boolean.FALSE); - } - if (command.equals(OpenClosedType.OPEN)) { - return Optional.of(Boolean.TRUE); - } - if (command.equals(OpenClosedType.CLOSED)) { - return Optional.of(Boolean.FALSE); - } - if (command instanceof DecimalType) { - return Optional.of(!command.equals(DecimalType.ZERO)); - } - return Optional.empty(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusCommunicationInterface.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusCommunicationInterface.java deleted file mode 100644 index 957e4d8398cf3..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusCommunicationInterface.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.concurrent.Future; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * Interface for interacting with a particular modbus slave. - * - * When no further communication is expected with the slave, close the interface so that any underlying resources can be - * freed. - * - * Close unregisters all the regular polls registered with registerRegularPoll. When endpoint's last - * communication interface is closed, the connection is closed as well, no matter the what EndpointPoolConfiguration - * says. - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public interface ModbusCommunicationInterface extends AutoCloseable { - - /** - * Get endpoint associated with this communication interface - * - * @return modbus slave endpoint - */ - public ModbusSlaveEndpoint getEndpoint(); - - /** - * Submit one-time poll task. The method returns immediately, and the execution of the poll task will happen in - * background. - * - * @param request request to send - * @param callback callback to call with data - * @param callback callback to call in case of failure - * @return future representing the polled task - * @throws IllegalStateException when this communication has been closed already - */ - public Future submitOneTimePoll(ModbusReadRequestBlueprint request, ModbusReadCallback resultCallback, - ModbusFailureCallback failureCallback); - - /** - * Register regularly polled task. The method returns immediately, and the execution of the poll task will happen in - * the background. - * - * One can register only one regular poll task for triplet of (endpoint, request, callback). - * - * @param request request to send - * @param pollPeriodMillis poll interval, in milliseconds - * @param initialDelayMillis initial delay before starting polling, in milliseconds - * @param callback callback to call with data - * @param callback callback to call in case of failure - * @return poll task representing the regular poll - * @throws IllegalStateException when this communication has been closed already - */ - public PollTask registerRegularPoll(ModbusReadRequestBlueprint request, long pollPeriodMillis, - long initialDelayMillis, ModbusReadCallback resultCallback, - ModbusFailureCallback failureCallback); - - /** - * Unregister regularly polled task - * - * If this communication interface is closed already, the method returns immediately with false return value - * - * @param task poll task to unregister - * @return whether poll task was unregistered. Poll task is not unregistered in case of unexpected errors or - * in the case where the poll task is not registered in the first place - */ - public boolean unregisterRegularPoll(PollTask task); - - /** - * Submit one-time write task. The method returns immediately, and the execution of the task will happen in - * background. - * - * @param request request to send - * @param callback callback to call with response - * @param callback callback to call in case of failure - * @return future representing the task - * @throws IllegalStateException when this communication has been closed already - */ - public Future submitOneTimeWrite(ModbusWriteRequestBlueprint request, ModbusWriteCallback resultCallback, - ModbusFailureCallback failureCallback); - - /** - * Close this communication interface and try to free all resources associated with it - * - * Upon close, all polling tasks registered by this instance are unregistered. In addition, connections are closed - * eagerly if this was the last connection interface pointing to the endpoint. - * - * After close, the communication interface cannot be used to communicate with the device. - * - */ - @Override - public void close() throws Exception; -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusConstants.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusConstants.java deleted file mode 100644 index 6a3230945218e..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusConstants.java +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Constants for Modbus transport - * - * == Regarding maximum read and write limits == - * - * Maximum number of registers that are allowed to be read. - * - * The Modbus protocol has many intepretation on maximum data size of messages. Good reference is here: - * https://wingpath.co.uk/manpage.php?product=modtest&page=message_limits.html - * - * We try to follow modern specification here (V1.1B3): - * https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf. See section 4.1 Protocol Specification in the - * specification. - * - * According to V1.1B3, maximum size for PDU is 253 bytes, making maximum ADU size 256 (RTU) or 260 (TCP). - * - * In the spec section 6, one can see maximum values for read and write counts. - * - * Note that this is not the only interpretation -- some sources limit the ADU to 256 also with TCP. - * In some cases, slaves cannot take in so much data. - * - * - * Reads are limited by response PDU size. - * Writes (FC15 & FC16) are limited by write request ADU size. - * - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusConstants { - - /** - * Value types for different number types. - * - * @author Sami Salonen - Initial contribution - * - */ - public static enum ValueType { - BIT("bit", 1), - INT8("int8", 8), - UINT8("uint8", 8), - INT16("int16", 16), - UINT16("uint16", 16), - INT32("int32", 32), - UINT32("uint32", 32), - FLOAT32("float32", 32), - INT64("int64", 64), - UINT64("uint64", 64), - - INT32_SWAP("int32_swap", 32), - UINT32_SWAP("uint32_swap", 32), - FLOAT32_SWAP("float32_swap", 32), - INT64_SWAP("int64_swap", 64), - UINT64_SWAP("uint64_swap", 64); - - private final String configValue; - private final int bits; - - ValueType(String configValue, int bits) { - this.configValue = configValue; - this.bits = bits; - } - - /** - * Returns number of bits represented by this ValueType - * - * @return number of bits - */ - public int getBits() { - return bits; - } - - /** - * Returns config value to refer to this value type - * - * @return config value as string - */ - public String getConfigValue() { - return configValue; - } - - /** - * Returns config value - */ - @Override - public String toString() { - return getConfigValue(); - } - - /** - * Constructs ValueType given the config value string. - * - * @param configValueType config value that will be parsed to ValueType - * @return ValueType matching the config value - * @throws IllegalArgumentException with unknown value types - */ - @SuppressWarnings("null") - public static @NonNull ValueType fromConfigValue(@Nullable String configValueType) - throws IllegalArgumentException { - return Stream.of(ValueType.values()).filter(v -> v.getConfigValue().equals(configValueType)).findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid valueType " + configValueType)); - } - } - - /** - * Maximum number of coils or discrete inputs that are allowed to be read. - * Limitation by Modbus protocol V1.1B3, 6.1 definition of Read Holding registers. - */ - public static final int MAX_BITS_READ_COUNT = 2000; - /** - * Maximum number of registers that are allowed to be read. - * Limitation by Modbus protocol V1.1B3, 6.3 definition of Read Coils. - */ - public static final int MAX_REGISTERS_READ_COUNT = 125; - /** - * Maximum number of coils or discrete inputs that are allowed to be written. - * Limitation by Modbus protocol V1.1B3, 6.11 definition of Write Multiple coils. - */ - public static final int MAX_BITS_WRITE_COUNT = 1968; - /** - * Maximum number of registers that are allowed to be written. - * Limitation by Modbus protocol V1.1B3, 6.12 definition of Write Multiple registers. - */ - public static final int MAX_REGISTERS_WRITE_COUNT = 123; -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusFailureCallback.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusFailureCallback.java deleted file mode 100644 index c4215e284f911..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusFailureCallback.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Callback used to report failure in Modbus - * - * @author Nagy Attila Gabor - Initial contribution - */ -@FunctionalInterface -@NonNullByDefault -public interface ModbusFailureCallback { - /** - * Callback handling response with error - * - * @param asyncModbusFailure details of the failure - */ - void handle(AsyncModbusFailure failure); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusManager.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusManager.java deleted file mode 100644 index 163b88745a271..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusManager.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * ModbusManager is the main interface for interacting with Modbus slaves - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusManager { - - /** - * Open communication interface to endpoint - * - * @param endpoint endpoint pointing to modbus slave - * @param configuration configuration for the endpoint - * @return Communication interface for interacting with the slave - * @throws IllegalArgumentException if there is already open communication interface with same endpoint but - * differing configuration - */ - public ModbusCommunicationInterface newModbusCommunicationInterface(ModbusSlaveEndpoint endpoint, - @Nullable EndpointPoolConfiguration configuration) throws IllegalArgumentException; - - /** - * Get general configuration settings applied to a given endpoint - * - * Note that default configuration settings are returned in case the endpoint has not been configured. - * - * @param endpoint endpoint to query - * @return general connection settings of the given endpoint - */ - public @Nullable EndpointPoolConfiguration getEndpointPoolConfiguration(ModbusSlaveEndpoint endpoint); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadCallback.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadCallback.java deleted file mode 100644 index 9c0492ff5479f..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadCallback.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Interface for read callbacks - * - * @author Sami Salonen - Initial contribution - */ -@FunctionalInterface -@NonNullByDefault -public interface ModbusReadCallback extends ModbusResultCallback { - - /** - * Callback handling response data - * - * @param result result of the read operation - */ - void handle(AsyncModbusReadResult result); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadFunctionCode.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadFunctionCode.java deleted file mode 100644 index 65e1dcc12ab74..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadFunctionCode.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -/** - * Modbus read function codes supported by this transport - * - * @author Sami Salonen - Initial contribution - */ -public enum ModbusReadFunctionCode { - READ_COILS, - READ_INPUT_DISCRETES, - READ_MULTIPLE_REGISTERS, - READ_INPUT_REGISTERS -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadRequestBlueprint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadRequestBlueprint.java deleted file mode 100644 index 67f81af517835..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadRequestBlueprint.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -import net.wimpi.modbus.Modbus; - -/** - * Implementation of immutable representation of modbus read request - * - * Equals and hashCode implemented keeping {@link PollTask} in mind: two instances of this class are considered the same - * if they have - * the equal parameters (same slave id, start, length, function code and maxTries). - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusReadRequestBlueprint { - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - static { - toStringStyle.setUseShortClassName(true); - } - - private final int slaveId; - private final ModbusReadFunctionCode functionCode; - private final int start; - private final int length; - private final int maxTries; - - public ModbusReadRequestBlueprint(int slaveId, ModbusReadFunctionCode functionCode, int start, int length, - int maxTries) { - this.slaveId = slaveId; - this.functionCode = functionCode; - this.start = start; - this.length = length; - this.maxTries = maxTries; - } - - /** - * 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. - */ - public int getUnitID() { - return slaveId; - } - - public int getReference() { - return start; - } - - public ModbusReadFunctionCode getFunctionCode() { - return functionCode; - } - - public int getDataLength() { - return length; - } - - /** - * Maximum number of tries to execute the request, when request fails - * - * For example, number 1 means on try only with no re-tries. - * - * @return number of maximum tries - */ - public int getMaxTries() { - return maxTries; - } - - /** - * 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. - */ - public int getProtocolID() { - return Modbus.DEFAULT_PROTOCOL_ID; - } - - @Override - public int hashCode() { - return new HashCodeBuilder(81, 3).append(slaveId).append(functionCode).append(start).append(length) - .append(maxTries).toHashCode(); - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("slaveId", slaveId).append("functionCode", functionCode) - .append("start", start).append("length", length).append("maxTries", maxTries).toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - return false; - } - ModbusReadRequestBlueprint rhs = (ModbusReadRequestBlueprint) obj; - return new EqualsBuilder().append(slaveId, rhs.slaveId).append(functionCode, rhs.functionCode) - .append(start, rhs.start).append(length, rhs.length).isEquals(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusRegisterArray.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusRegisterArray.java deleted file mode 100644 index 6246d34b2a02d..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusRegisterArray.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.Arrays; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.util.HexUtils; - -/** - * Immutable {@link ModbusRegisterArray} implementation - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ModbusRegisterArray { - - private final byte[] bytes; - - public ModbusRegisterArray(byte... bytes) { - if (bytes.length % 2 != 0) { - throw new IllegalArgumentException(); - } - this.bytes = Arrays.copyOf(bytes, bytes.length); - } - - /** - * Construct plain ModbusRegisterArray array from register values - * - * @param registerValues register values, each int corresponding to one register - * @return - */ - public ModbusRegisterArray(int... registerValues) { - bytes = new byte[registerValues.length * 2]; - for (int registerIndex = 0; registerIndex < registerValues.length; registerIndex++) { - int register = registerValues[registerIndex] & 0xffff; - // hi-byte - bytes[registerIndex * 2] = (byte) (register >> 8); - // lo byte - bytes[registerIndex * 2 + 1] = (byte) register; - } - } - - /** - * Get register index i as unsigned integer - * - * @param i register index - * @return register value interpreted as unsigned integer (big-endian byte ordering) - */ - public int getRegister(int i) { - int hi = bytes[i * 2] & 0xff; - int lo = bytes[i * 2 + 1] & 0xff; - return ((hi << 8) | lo) & 0xffff; - } - - /** - * Return bytes representing the registers - * - * - * Index 0: hi-byte of 1st register - * Index 1: low-byte of 1st register - * Index 3: hi-byte of 2nd register - * Index 4: low-byte of 2nd register - * ... - * - * @return set of bytes - */ - public byte[] getBytes() { - return bytes; - } - - /** - * Get number of registers stored in this instance - * - * @return - */ - public int size() { - return bytes.length / 2; - } - - @Override - public String toString() { - if (bytes.length == 0) { - return "ModbusRegisterArray()"; - } - return new StringBuilder(bytes.length).append("ModbusRegisterArray(").append(toHexString()).append(')') - .toString(); - } - - /** - * Get register data as a hex string - * - * For example, 04 45 00 00 - * - * @return string representing the bytes of the register array - */ - public String toHexString() { - if (size() == 0) { - return ""; - } - return HexUtils.bytesToHex(getBytes()); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResponse.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResponse.java deleted file mode 100644 index d135016a588c0..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResponse.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Minimal representation of a modbus response. - * - * Only function code is exposed, which allows detecting MODBUS exception codes from normal codes. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusResponse { - - /** - * Function code of the response. - * - * Note that in case of Slave responding with Modbus exception response, the response - * function code might differ from request function code - * - * @return function code of the response - */ - public int getFunctionCode(); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResultCallback.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResultCallback.java deleted file mode 100644 index eb0ca3e7b6929..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusResultCallback.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Base interface for callbacks used in Modbus - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusResultCallback { -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCallback.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCallback.java deleted file mode 100644 index fdb83f47fdd78..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCallback.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Interface for write callbacks - * - * @author Sami Salonen - Initial contribution - */ -@FunctionalInterface -@NonNullByDefault -public interface ModbusWriteCallback extends ModbusResultCallback { - - /** - * Callback handling response data - * - * @param asyncModbusWriteResult result of the write operation - */ - void handle(AsyncModbusWriteResult result); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCoilRequestBlueprint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCoilRequestBlueprint.java deleted file mode 100644 index 505ce785cc1f3..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteCoilRequestBlueprint.java +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Implementation for writing coils - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusWriteCoilRequestBlueprint extends ModbusWriteRequestBlueprint { - - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - - static { - toStringStyle.setUseShortClassName(true); - } - - private final int slaveId; - private final int reference; - private final BitArray bits; - private final boolean writeMultiple; - private final int maxTries; - - /** - * Construct coil write request with single bit of data - * - * @param slaveId slave id to write to - * @param reference reference address - * @param data bit to write - * @param writeMultiple whether to use {@link ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS} over - * {@link ModbusWriteFunctionCode.WRITE_COIL} - * @param maxTries maximum number of tries in case of errors, should be at least 1 - */ - public ModbusWriteCoilRequestBlueprint(int slaveId, int reference, boolean data, boolean writeMultiple, - int maxTries) { - this(slaveId, reference, new BitArray(data), writeMultiple, maxTries); - } - - /** - * Construct coil write request with many bits of data - * - * @param slaveId slave id to write to - * @param reference reference address - * @param data bit(s) to write - * @param writeMultiple whether to use {@link ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS} over - * {@link ModbusWriteFunctionCode.WRITE_COIL}. Useful with single bit of data. - * @param maxTries maximum number of tries in case of errors, should be at least 1 - * @throws IllegalArgumentException in case data is empty, writeMultiple is - * false but there are many bits to write. - */ - public ModbusWriteCoilRequestBlueprint(int slaveId, int reference, BitArray data, boolean writeMultiple, - int maxTries) { - super(); - this.slaveId = slaveId; - this.reference = reference; - this.bits = data; - this.writeMultiple = writeMultiple; - this.maxTries = maxTries; - - if (!writeMultiple && bits.size() > 1) { - throw new IllegalArgumentException("With multiple coils, writeMultiple must be true"); - } - if (bits.size() == 0) { - throw new IllegalArgumentException("Must have at least one bit"); - } - if (maxTries <= 0) { - throw new IllegalArgumentException("maxTries should be positive, was " + maxTries); - } - } - - @Override - public int getUnitID() { - return slaveId; - } - - @Override - public int getReference() { - return reference; - } - - @Override - public ModbusWriteFunctionCode getFunctionCode() { - return writeMultiple ? ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS : ModbusWriteFunctionCode.WRITE_COIL; - } - - public BitArray getCoils() { - return bits; - } - - @Override - public int getMaxTries() { - return maxTries; - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("slaveId", slaveId).append("reference", reference) - .append("functionCode", getFunctionCode()).append("bits", bits).append("maxTries", maxTries).toString(); - } - - @Override - public void accept(ModbusWriteRequestBlueprintVisitor visitor) { - visitor.visit(this); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteFunctionCode.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteFunctionCode.java deleted file mode 100644 index 9bc160bc48432..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteFunctionCode.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNull; - -import net.wimpi.modbus.Modbus; - -/** - * Modbus write function codes supported by this transport - * - * @author Sami Salonen - Initial contribution - */ -public enum ModbusWriteFunctionCode { - WRITE_COIL(Modbus.WRITE_COIL), - WRITE_MULTIPLE_COILS(Modbus.WRITE_MULTIPLE_COILS), - WRITE_SINGLE_REGISTER(Modbus.WRITE_SINGLE_REGISTER), - WRITE_MULTIPLE_REGISTERS(Modbus.WRITE_MULTIPLE_REGISTERS); - - private final int functionCode; - - ModbusWriteFunctionCode(int code) { - functionCode = code; - } - - /** - * Get numeric function code represented by this instance - * - * @return - */ - public int getFunctionCode() { - return functionCode; - } - - /** - * Construct {@link ModbusWriteFunctionCode} from the numeric function code - * - * @param functionCode numeric function code - * @return {@link ModbusWriteFunctionCode} matching the numeric function code - * @throws IllegalArgumentException with unsupported functions - */ - @SuppressWarnings("null") - public static @NonNull ModbusWriteFunctionCode fromFunctionCode(int functionCode) throws IllegalArgumentException { - return Stream.of(ModbusWriteFunctionCode.values()).filter(v -> v.getFunctionCode() == functionCode).findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid functionCode")); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRegisterRequestBlueprint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRegisterRequestBlueprint.java deleted file mode 100644 index 83c2103760add..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRegisterRequestBlueprint.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Implementation for writing registers - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusWriteRegisterRequestBlueprint extends ModbusWriteRequestBlueprint { - - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - - static { - toStringStyle.setUseShortClassName(true); - } - - private final int slaveId; - private final int reference; - private final ModbusRegisterArray registers; - private final boolean writeMultiple; - private final int maxTries; - - /** - * Construct coil write request with many bits of data - * - * @param slaveId slave id to write to - * @param reference reference address - * @param registers register(s) to write - * @param writeMultiple whether to use {@link ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS} over - * {@link ModbusWriteFunctionCode.WRITE_COIL}. Useful with single register of data. - * @param maxTries maximum number of tries in case of errors, should be at least 1 - * @throws IllegalArgumentException in case data is empty, writeMultiple is - * false but there are many registers to write. - */ - public ModbusWriteRegisterRequestBlueprint(int slaveId, int reference, ModbusRegisterArray registers, - boolean writeMultiple, int maxTries) throws IllegalArgumentException { - super(); - this.slaveId = slaveId; - this.reference = reference; - this.registers = registers; - this.writeMultiple = writeMultiple; - this.maxTries = maxTries; - - if (!writeMultiple && registers.size() > 1) { - throw new IllegalArgumentException("With multiple registers, writeMultiple must be true"); - } - if (registers.size() == 0) { - throw new IllegalArgumentException("Must have at least one register"); - } - if (maxTries <= 0) { - throw new IllegalArgumentException("maxTries should be positive"); - } - } - - @Override - public int getReference() { - return reference; - } - - @Override - public int getUnitID() { - return slaveId; - } - - @Override - public ModbusWriteFunctionCode getFunctionCode() { - return writeMultiple ? ModbusWriteFunctionCode.WRITE_MULTIPLE_REGISTERS - : ModbusWriteFunctionCode.WRITE_SINGLE_REGISTER; - } - - public ModbusRegisterArray getRegisters() { - return registers; - } - - @Override - public int getMaxTries() { - return maxTries; - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("slaveId", slaveId).append("reference", reference) - .append("functionCode", getFunctionCode()).append("registers", registers).append("maxTries", maxTries) - .toString(); - } - - @Override - public void accept(ModbusWriteRequestBlueprintVisitor visitor) { - visitor.visit(this); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprint.java deleted file mode 100644 index 5cab106286150..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprint.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -import net.wimpi.modbus.Modbus; - -/** - * Base interface for Modbus write requests - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public abstract class ModbusWriteRequestBlueprint { - - /** - * 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. - */ - public int getProtocolID() { - return Modbus.DEFAULT_PROTOCOL_ID; - } - - /** - * Returns the reference of the register/coil/discrete input to to start - * writing with this request - *

- * - * @return the reference of the register - * to start reading from as int. - */ - public abstract int getReference(); - - /** - * 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. - */ - public abstract 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 - * net.wimpi.modbus.Modbus. - *

- * - * @return the function code as int. - * - * @see net.wimpi.modbus.Modbus - */ - public abstract ModbusWriteFunctionCode getFunctionCode(); - - /** - * Get maximum number of tries, in case errors occur. Should be at least 1. - */ - public abstract int getMaxTries(); - - /** - * Accept visitor - * - * @param visitor - */ - public abstract void accept(ModbusWriteRequestBlueprintVisitor visitor); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprintVisitor.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprintVisitor.java deleted file mode 100644 index ab24d4cccac8b..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusWriteRequestBlueprintVisitor.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - *

- * ModbusWriteRequestBlueprintVisitor interface. - *

- * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusWriteRequestBlueprintVisitor { - - /** - * Visit request writing coil data - * - * @param blueprint - */ - public void visit(ModbusWriteCoilRequestBlueprint blueprint); - - /** - * Visit request writing register data - * - * @param blueprint - */ - public void visit(ModbusWriteRegisterRequestBlueprint blueprint); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/PollTask.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/PollTask.java deleted file mode 100644 index bda4ff5737ec7..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/PollTask.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Poll task represents Modbus read request - * - * Must be hashable. HashCode and equals should be defined such that no two poll tasks are registered that are - * equal. - * - * @author Sami Salonen - Initial contribution - * - * @see ModbusManager.registerRegularPoll - */ -@NonNullByDefault -public interface PollTask extends - TaskWithEndpoint> { - @Override - default int getMaxTries() { - return getRequest().getMaxTries(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/TaskWithEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/TaskWithEndpoint.java deleted file mode 100644 index ef36691d37c40..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/TaskWithEndpoint.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * Common base interface for read and write tasks. - * - * @author Sami Salonen - Initial contribution - * - * @param request type - * @param callback type - */ -@NonNullByDefault -public interface TaskWithEndpoint> { - /** - * Gets endpoint associated with this task - * - * @return - */ - ModbusSlaveEndpoint getEndpoint(); - - /** - * Gets request associated with this task - * - * @return - */ - R getRequest(); - - /** - * Gets the result callback associated with this task, will be called with response - * - * @return - */ - C getResultCallback(); - - /** - * Gets the failure callback associated with this task, will be called in case of an error - * - * @return - */ - F getFailureCallback(); - - int getMaxTries(); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ValueBuffer.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ValueBuffer.java deleted file mode 100644 index bcf5aa358e968..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ValueBuffer.java +++ /dev/null @@ -1,331 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import java.math.BigInteger; -import java.nio.BufferOverflowException; -import java.nio.InvalidMarkException; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * ByteBuffer-like interface for working with different types of data stored in byte arrays - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ValueBuffer { - private final byte[] bytes; - private final AtomicInteger byteIndex = new AtomicInteger(); - private volatile AtomicReference<@Nullable AtomicInteger> mark = new AtomicReference<>(); - - /** - * Wrap modbus registers and create a new instance of ValueBuffer - * - * The instance will have position of 0. - * - * @param array set of registers - * @return new instance of ValueBuffer referencing bytes represented by modbus register array - */ - public static ValueBuffer wrap(ModbusRegisterArray array) { - return new ValueBuffer(array.getBytes()); - } - - /** - * Wrap given bytes and create a new instance of ValueBuffer - * - * The instance will have position of 0. - * - * - * @param array set of bytes to wrap - * @return new instance of ValueBuffer referencing bytes - */ - public static ValueBuffer wrap(byte[] array) { - return new ValueBuffer(array); - } - - private ValueBuffer(byte[] bytes) { - this.bytes = bytes; - } - - /** - * Returns this buffer's position. - * - * @return The position of this buffer - */ - public int position() { - return byteIndex.get(); - } - - /** - * Sets this buffer's position. If the mark is defined and larger than the new position then it is discarded. - * - * @return this buffer - */ - public ValueBuffer position(int byteIndex) { - this.mark.getAndUpdate(curMark -> { - if (curMark == null) { - return null; - } else if (curMark.get() > byteIndex) { - return null; - } else { - return curMark; - } - }); - this.byteIndex.set(byteIndex); - return this; - } - - /** - * Sets this buffer's mark at its position. - * - * @return this buffer - */ - public ValueBuffer mark() { - mark = new AtomicReference<>(new AtomicInteger(byteIndex.get())); - return this; - } - - /** - * Resets this buffer's position to the previously-marked position. - * Invoking this method neither changes nor discards the mark's value. - * - * @return this buffer - * @throws InvalidMarkException If the mark has not been set - */ - public ValueBuffer reset() throws InvalidMarkException { - int mark = Optional.ofNullable(this.mark.get()).map(i -> i.get()).orElse(-1); - if (mark < 0) { - throw new InvalidMarkException(); - } - byteIndex.set(mark); - return this; - } - - /** - * Returns the number of bytes between the current position and the end. - * - * @return The number of bytes remaining in this buffer - */ - public int remaining() { - return bytes.length - byteIndex.get(); - } - - /** - * Returns underlying bytes - * - * @return reference to underlying bytes - */ - public byte[] array() { - return bytes; - } - - /** - * Tells whether there are any bytes left between current position and the end - * - * @return true if, and only if, there is at least one byte remaining in this buffer - */ - public boolean hasRemaining() { - return remaining() > 0; - } - - /** - * Starting from current position, read dst.length number of bytes and copy the data to dst - * - * @param dst copied bytes - * @return this buffer - * @throws BufferOverflowException If there is insufficient space in this buffer for the remaining bytes in the - * source buffer - */ - public ValueBuffer get(byte[] dst) { - int start = byteIndex.getAndAdd(dst.length); - try { - System.arraycopy(bytes, start, dst, 0, dst.length); - } catch (IndexOutOfBoundsException e) { - throw new BufferOverflowException(); - } - return this; - } - - /** - * Extract signed 8-bit integer at current position, and advance position. - * - * @return signed 8-bit integer (byte) - * @see ModbusBitUtilities.extractSInt8 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public byte getSInt8() { - return ModbusBitUtilities.extractSInt8(bytes, byteIndex.getAndAdd(1)); - } - - /** - * Extract unsigned 8-bit integer at current position, and advance position. - * - * @return unsigned 8-bit integer - * @see ModbusBitUtilities.extractUInt8 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public short getUInt8() { - return ModbusBitUtilities.extractUInt8(bytes, byteIndex.getAndAdd(1)); - } - - /** - * Extract signed 16-bit integer at current position, and advance position. - * - * @return signed 16-bit integer (short) - * @see ModbusBitUtilities.extractSInt16 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public short getSInt16() { - return ModbusBitUtilities.extractSInt16(bytes, byteIndex.getAndAdd(2)); - } - - /** - * Extract unsigned 16-bit integer at current position, and advance position. - * - * @return unsigned 16-bit integer - * @see ModbusBitUtilities.extractUInt16 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public int getUInt16() { - return ModbusBitUtilities.extractUInt16(bytes, byteIndex.getAndAdd(2)); - } - - /** - * Extract signed 32-bit integer at current position, and advance position. - * - * @return signed 32-bit integer - * @see ModbusBitUtilities.extractSInt32 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public int getSInt32() { - return ModbusBitUtilities.extractSInt32(bytes, byteIndex.getAndAdd(4)); - } - - /** - * Extract unsigned 32-bit integer at current position, and advance position. - * - * @return unsigned 32-bit integer - * @see ModbusBitUtilities.extractUInt32 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public long getUInt32() { - return ModbusBitUtilities.extractUInt32(bytes, byteIndex.getAndAdd(4)); - } - - /** - * Extract signed 32-bit integer at current position, and advance position. - * - * This is identical with getSInt32, but with registers swapped. - * - * @return signed 32-bit integer - * @see ModbusBitUtilities.extractSInt32Swap - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public int getSInt32Swap() { - return ModbusBitUtilities.extractSInt32Swap(bytes, byteIndex.getAndAdd(4)); - } - - /** - * Extract unsigned 32-bit integer at current position, and advance position. - * - * This is identical with getUInt32, but with registers swapped. - * - * @return unsigned 32-bit integer - * @see ModbusBitUtilities.extractUInt32Swap - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public long getUInt32Swap() { - return ModbusBitUtilities.extractUInt32Swap(bytes, byteIndex.getAndAdd(4)); - } - - /** - * Extract signed 64-bit integer at current position, and advance position. - * - * @return signed 64-bit integer - * @see ModbusBitUtilities.extractInt64 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public long getSInt64() { - return ModbusBitUtilities.extractSInt64(bytes, byteIndex.getAndAdd(8)); - } - - /** - * Extract unsigned 64-bit integer at current position, and advance position. - * - * @return unsigned 64-bit integer - * @see ModbusBitUtilities.extractUInt64 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public BigInteger getUInt64() { - return ModbusBitUtilities.extractUInt64(bytes, byteIndex.getAndAdd(8)); - } - - /** - * Extract signed 64-bit integer at current position, and advance position. - * - * This is identical with getSInt64, but with registers swapped. - * - * @return signed 64-bit integer - * @see ModbusBitUtilities.extractInt64Swap - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public long getSInt64Swap() { - return ModbusBitUtilities.extractSInt64Swap(bytes, byteIndex.getAndAdd(8)); - } - - /** - * Extract unsigned 64-bit integer at current position, and advance position. - * - * This is identical with getUInt64, but with registers swapped. - * - * @return unsigned 64-bit integer - * @see ModbusBitUtilities.extractUInt64Swap - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public BigInteger getUInt64Swap() { - return ModbusBitUtilities.extractUInt64Swap(bytes, byteIndex.getAndAdd(8)); - } - - /** - * Extract single-precision 32-bit IEEE 754 floating point at current position, and advance position. - * - * Note that this method can return floating point NaN and floating point infinity. - * - * @return single-precision 32-bit IEEE 754 floating point - * @see ModbusBitUtilities.extractFloat32 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public float getFloat32() { - return ModbusBitUtilities.extractFloat32(bytes, byteIndex.getAndAdd(4)); - } - - /** - * Extract single-precision 32-bit IEEE 754 floating point at current position, and advance position. - * - * This is identical with getFloat32, but with registers swapped. - * - * Note that this method can return floating point NaN and floating point infinity. - * - * @return single-precision 32-bit IEEE 754 floating point - * @see ModbusBitUtilities.extractFloat32 - * @throws IllegalArgumentException when there are not enough bytes in this ValueBuffer - */ - public float getFloat32Swap() { - return ModbusBitUtilities.extractFloat32Swap(bytes, byteIndex.getAndAdd(4)); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/WriteTask.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/WriteTask.java deleted file mode 100644 index 079e053e29e3b..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/WriteTask.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Poll task represents Modbus write request - * - * Unlike {@link PollTask}, this does not have to be hashable. - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public interface WriteTask extends - TaskWithEndpoint> { - @Override - default int getMaxTries() { - return getRequest().getMaxTries(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/EndpointPoolConfiguration.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/EndpointPoolConfiguration.java deleted file mode 100644 index 44f1cbfb6fa3a..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/EndpointPoolConfiguration.java +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Class representing pooling related configuration of a single endpoint - * - * This class implements equals hashcode constract, and thus is suitable for use as keys in HashMaps, for example. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class EndpointPoolConfiguration { - - /** - * How long should be the minimum duration between previous transaction end and the next transaction with the same - * endpoint. - * - * In milliseconds. - */ - private long interTransactionDelayMillis; - - /** - * How long should be the minimum duration between connection-establishments from the pool (with same endpoint). In - * milliseconds. - */ - private long interConnectDelayMillis; - - /** - * How many times we want to try connecting to the endpoint before giving up. One means that connection - * establishment is tried once. - */ - private int connectMaxTries = 1; - - /** - * Re-connect connection every X milliseconds. Negative means that connection is not disconnected automatically. - * One can use 0ms to denote reconnection after every transaction (default). - */ - private int reconnectAfterMillis; - - /** - * How long before we give up establishing the connection. In milliseconds. Default of 0 means that system/OS - * default is respected. - */ - private int connectTimeoutMillis; - - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - - static { - toStringStyle.setUseShortClassName(true); - } - - public long getInterConnectDelayMillis() { - return interConnectDelayMillis; - } - - public void setInterConnectDelayMillis(long interConnectDelayMillis) { - this.interConnectDelayMillis = interConnectDelayMillis; - } - - public int getConnectMaxTries() { - return connectMaxTries; - } - - public void setConnectMaxTries(int connectMaxTries) { - this.connectMaxTries = connectMaxTries; - } - - public int getReconnectAfterMillis() { - return reconnectAfterMillis; - } - - public void setReconnectAfterMillis(int reconnectAfterMillis) { - this.reconnectAfterMillis = reconnectAfterMillis; - } - - public long getInterTransactionDelayMillis() { - return interTransactionDelayMillis; - } - - public void setInterTransactionDelayMillis(long interTransactionDelayMillis) { - this.interTransactionDelayMillis = interTransactionDelayMillis; - } - - public int getConnectTimeoutMillis() { - return connectTimeoutMillis; - } - - public void setConnectTimeoutMillis(int connectTimeoutMillis) { - this.connectTimeoutMillis = connectTimeoutMillis; - } - - @Override - public int hashCode() { - return new HashCodeBuilder(2149, 3117).append(interTransactionDelayMillis).append(interConnectDelayMillis) - .append(connectMaxTries).append(reconnectAfterMillis).append(connectTimeoutMillis).toHashCode(); - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle) - .append("interTransactionDelayMillis", interTransactionDelayMillis) - .append("interConnectDelayMillis", interConnectDelayMillis).append("connectMaxTries", connectMaxTries) - .append("reconnectAfterMillis", reconnectAfterMillis) - .append("connectTimeoutMillis", connectTimeoutMillis).toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - return false; - } - EndpointPoolConfiguration rhs = (EndpointPoolConfiguration) obj; - return new EqualsBuilder().append(interTransactionDelayMillis, rhs.interTransactionDelayMillis) - .append(interConnectDelayMillis, rhs.interConnectDelayMillis) - .append(connectMaxTries, rhs.connectMaxTries).append(reconnectAfterMillis, rhs.reconnectAfterMillis) - .append(connectTimeoutMillis, rhs.connectTimeoutMillis).isEquals(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusIPSlaveEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusIPSlaveEndpoint.java deleted file mode 100644 index a1d891c05b99b..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusIPSlaveEndpoint.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Common base class for ip based endpoints. Endpoint differentiates different modbus slaves only by the ip address - * (string) and port name. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public abstract class ModbusIPSlaveEndpoint implements ModbusSlaveEndpoint { - - private String address; - private int port; - - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - - static { - toStringStyle.setUseShortClassName(true); - } - - public ModbusIPSlaveEndpoint(String address, int port) { - this.address = address; - this.port = port; - } - - public String getAddress() { - return address; - } - - public int getPort() { - return port; - } - - @Override - public int hashCode() { - // differentiate different protocols using the class name, and after that use address and port - int protocolHash = this.getClass().getName().hashCode(); - if (protocolHash % 2 == 0) { - protocolHash += 1; - } - return new HashCodeBuilder(11, protocolHash).append(address).append(port).toHashCode(); - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("address", address).append("port", port).toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - // different protocol -> not equal! - return false; - } - ModbusIPSlaveEndpoint rhs = (ModbusIPSlaveEndpoint) obj; - return new EqualsBuilder().append(address, rhs.address).append(port, rhs.port).isEquals(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSerialSlaveEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSerialSlaveEndpoint.java deleted file mode 100644 index a335185911ef6..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSerialSlaveEndpoint.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -import net.wimpi.modbus.util.SerialParameters; - -/** - * Serial endpoint. Endpoint differentiates different modbus slaves only by the serial port. - * port. - * - * Endpoint contains SerialParameters which should be enough to establish the connection. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ModbusSerialSlaveEndpoint implements ModbusSlaveEndpoint { - - private SerialParameters serialParameters; - private static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - - static { - toStringStyle.setUseShortClassName(true); - } - - public ModbusSerialSlaveEndpoint(String portName, int baudRate, int flowControlIn, int flowControlOut, int databits, - int stopbits, int parity, String encoding, boolean echo, int receiveTimeoutMillis) { - this(new SerialParameters(portName, baudRate, flowControlIn, flowControlOut, databits, stopbits, parity, - encoding, echo, receiveTimeoutMillis)); - } - - public ModbusSerialSlaveEndpoint(String portName, int baudRate, String flowControlIn, String flowControlOut, - int databits, String stopbits, String parity, String encoding, boolean echo, int receiveTimeoutMillis) { - SerialParameters parameters = new SerialParameters(); - parameters.setPortName(portName); - parameters.setBaudRate(baudRate); - parameters.setFlowControlIn(flowControlIn); - parameters.setFlowControlOut(flowControlOut); - parameters.setDatabits(databits); - parameters.setStopbits(stopbits); - parameters.setParity(parity); - parameters.setEncoding(encoding); - parameters.setEcho(echo); - parameters.setReceiveTimeoutMillis(receiveTimeoutMillis); - this.serialParameters = parameters; - } - - private ModbusSerialSlaveEndpoint(SerialParameters serialParameters) { - this.serialParameters = serialParameters; - } - - public SerialParameters getSerialParameters() { - return serialParameters; - } - - @Override - public R accept(ModbusSlaveEndpointVisitor factory) { - return factory.visit(this); - } - - public String getPortName() { - return serialParameters.getPortName(); - } - - @Override - public int hashCode() { - // hashcode & equal is determined purely by port name - return serialParameters.getPortName().hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - // equals is determined purely by port name - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - return false; - } - ModbusSerialSlaveEndpoint rhs = (ModbusSerialSlaveEndpoint) obj; - return new EqualsBuilder().append(serialParameters.getPortName(), rhs.serialParameters.getPortName()) - .isEquals(); - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("portName", serialParameters.getPortName()).toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpoint.java deleted file mode 100644 index ab0617a377776..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpoint.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * ModbusSlaveEndpoint contains minimal connection information to establish connection to the slave. End point equals - * and hashCode methods should be implemented such that - * they can be used to differentiate different physical slaves. Read and write transactions are processed - * one at a time if they are associated with the same endpoint (in the sense of equals and hashCode). - * - * Note that, endpoint class might not include all configuration that might be necessary to actually - * communicate with the slave, just the data that is required to establish the connection. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusSlaveEndpoint { - public R accept(ModbusSlaveEndpointVisitor visitor); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpointVisitor.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpointVisitor.java deleted file mode 100644 index 759cbd3de84c7..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusSlaveEndpointVisitor.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Visitor for ModbusSlaveEndpoint - * - * @param return type from visit - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusSlaveEndpointVisitor { - - @Nullable - R visit(ModbusTCPSlaveEndpoint endpoint); - - @Nullable - R visit(ModbusSerialSlaveEndpoint endpoint); - - @Nullable - R visit(ModbusUDPSlaveEndpoint endpoint); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusTCPSlaveEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusTCPSlaveEndpoint.java deleted file mode 100644 index 177fa538810d4..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusTCPSlaveEndpoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Endpoint for TCP slaves - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusTCPSlaveEndpoint extends ModbusIPSlaveEndpoint { - - public ModbusTCPSlaveEndpoint(String address, int port) { - super(address, port); - } - - @Override - public R accept(ModbusSlaveEndpointVisitor factory) { - return factory.visit(this); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusUDPSlaveEndpoint.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusUDPSlaveEndpoint.java deleted file mode 100644 index 33499980ac019..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/endpoint/ModbusUDPSlaveEndpoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.endpoint; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Endpoint for UDP slaves - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusUDPSlaveEndpoint extends ModbusIPSlaveEndpoint { - - public ModbusUDPSlaveEndpoint(String address, int port) { - super(address, port); - } - - @Override - public R accept(ModbusSlaveEndpointVisitor factory) { - return factory.visit(this); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusConnectionException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusConnectionException.java deleted file mode 100644 index c18669630d59e..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusConnectionException.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * Exception for connection issues - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusConnectionException extends ModbusTransportException { - - private static final long serialVersionUID = -6171226761518661925L; - private ModbusSlaveEndpoint endpoint; - - /** - * - * @param endpoint endpoint associated with this exception - */ - public ModbusConnectionException(ModbusSlaveEndpoint endpoint) { - this.endpoint = endpoint; - } - - /** - * Get endpoint associated with this connection error - * - * @return endpoint with the error - */ - public ModbusSlaveEndpoint getEndpoint() { - return endpoint; - } - - @Override - public @Nullable String getMessage() { - return String.format("Error connecting to endpoint %s", endpoint); - } - - @Override - public String toString() { - return String.format("ModbusConnectionException(Error connecting to endpoint=%s)", endpoint); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveErrorResponseException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveErrorResponseException.java deleted file mode 100644 index bccd7f405a9b8..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveErrorResponseException.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Exception for explicit exception responses from Modbus slave - * - * @author Sami Salonen - Initial contribution - * @author Nagy Attila Gabor - added getter for error type - * - */ -@NonNullByDefault -public abstract class ModbusSlaveErrorResponseException extends ModbusTransportException { - - /** - * The function code received in the query is not an allowable action for the slave. This may be because the - * function code is only applicable to newer devices, and was not implemented in the unit selected. It could also - * indicate that the slave is in the wrong state to process a request of this type, for example because it is - * unconfigured and is being asked to return register values. If a Poll Program Complete command was issued, this - * code indicates that no program function preceded it. - */ - public static final int ILLEGAL_FUNCTION = 1; - - /** - * The data address received in the query is not an allowable address for the slave. More specifically, the - * combination of reference number and transfer length is invalid. For a controller with 100 registers, a request - * with offset 96 and length 4 would succeed, a request with offset 96 and length 5 will generate exception 02. - */ - public static final int ILLEGAL_DATA_ACCESS = 2; - - /** - * A value contained in the query data field is not an allowable value for the slave. This indicates a fault in the - * structure of remainder of a complex request, such as that the implied length is incorrect. It specifically does - * NOT mean that a data item submitted for storage in a register has a value outside the expectation of the - * application program, since the Modbus protocol is unaware of the significance of any particular value of any - * particular register. - */ - public static final int ILLEGAL_DATA_VALUE = 3; - - /** - * An unrecoverable error occurred while the slave was attempting to perform the requested action. - */ - public static final int SLAVE_DEVICE_FAILURE = 4; - - /** - * Specialized use in conjunction with programming commands. - * The slave has accepted the request and is processing it, but a long duration of time will be required to do so. - * This response is returned to prevent a timeout error from occurring in the master. The master can next issue a - * Poll Program Complete message to determine if processing is completed. - */ - public static final int ACKNOWLEDGE = 5; - - /** - * Specialized use in conjunction with programming commands. - * The slave is engaged in processing a long-duration program command. The master should retransmit the message - * later when the slave is free. - */ - public static final int SLAVE_DEVICE_BUSY = 6; - - /** - * The slave cannot perform the program function received in the query. This code is returned for an unsuccessful - * programming request using function code 13 or 14 decimal. The master should request diagnostic or error - * information from the slave. - */ - public static final int NEGATIVE_ACKNOWLEDGE = 7; - - /** - * Specialized use in conjunction with function codes 20 and 21 and reference type 6, to indicate that the extended - * file area failed to pass a consistency check. - * The slave attempted to read extended memory or record file, but detected a parity error in memory. The master can - * retry the request, but service may be required on the slave device. - */ - public static final int MEMORY_PARITY_ERROR = 8; - - /** - * Specialized use in conjunction with gateways, indicates that the gateway was unable to allocate an internal - * communication path from the input port to the output port for processing the request. Usually means the gateway - * is misconfigured or overloaded. - */ - public static final int GATEWAY_PATH_UNVAVAILABLE = 10; - - /** - * Specialized use in conjunction with gateways, indicates that no response was obtained from the target device. - * Usually means that the device is not present on the network. - */ - public static final int GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 11; - - private static final long serialVersionUID = -1435199498550990487L; - - /** - * @return the Modbus exception code that happened - */ - public abstract int getExceptionCode(); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveIOException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveIOException.java deleted file mode 100644 index e1c377ed1c25c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusSlaveIOException.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Exception for all IO errors - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusSlaveIOException extends ModbusTransportException { - - private static final long serialVersionUID = -8568199166837844463L; -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusTransportException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusTransportException.java deleted file mode 100644 index 5c485ee521abc..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusTransportException.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Base exception for all exceptions in Modbus transport bundle - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusTransportException extends Exception { - - private static final long serialVersionUID = 1684767401685843339L; -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseFunctionCodeException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseFunctionCodeException.java deleted file mode 100644 index ff9e2f6fa11d8..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseFunctionCodeException.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Exception representing situation where function code of the response does not match request - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusUnexpectedResponseFunctionCodeException extends ModbusTransportException { - - private static final long serialVersionUID = 1109165449703638949L; - private int requestFunctionCode; - private int responseFunctionCode; - - public ModbusUnexpectedResponseFunctionCodeException(int requestFunctionCode, int responseFunctionCode) { - this.requestFunctionCode = requestFunctionCode; - this.responseFunctionCode = responseFunctionCode; - } - - @Override - public @Nullable String getMessage() { - return String.format("Function code of request (%d) does not equal response (%d)", requestFunctionCode, - responseFunctionCode); - } - - @Override - public String toString() { - return String.format( - "ModbusUnexpectedResponseFunctionCodeException(requestFunctionCode=%d, responseFunctionCode=%d)", - requestFunctionCode, responseFunctionCode); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseSizeException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseSizeException.java deleted file mode 100644 index 76a8cef11f34f..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedResponseSizeException.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Exception representing situation where data length of the response does not match request - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusUnexpectedResponseSizeException extends ModbusTransportException { - - private static final long serialVersionUID = 2460907938819984483L; - private int requestSize; - private int responseSize; - - public ModbusUnexpectedResponseSizeException(int requestSize, int responseSize) { - this.requestSize = requestSize; - this.responseSize = responseSize; - } - - @Override - public @Nullable String getMessage() { - return String.format("Data length of the request (%d) does not equal response (%d). Slave response is invalid.", - requestSize, responseSize); - } - - @Override - public String toString() { - return String.format("ModbusUnexpectedResponseSizeException(requestFunctionCode=%d, responseFunctionCode=%d)", - requestSize, responseSize); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedTransactionIdException.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedTransactionIdException.java deleted file mode 100644 index 36d8fc3c5b542..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/exception/ModbusUnexpectedTransactionIdException.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.exception; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Exception representing situation where transaction id of the response does not match request - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusUnexpectedTransactionIdException extends ModbusTransportException { - - private static final long serialVersionUID = -2453232634024813933L; - private int requestId; - private int responseId; - - public ModbusUnexpectedTransactionIdException(int requestId, int responseId) { - this.requestId = requestId; - this.responseId = responseId; - } - - @Override - public @Nullable String getMessage() { - return String.format("Transaction id of request (%d) does not equal response (%d). Slave response is invalid.", - requestId, responseId); - } - - @Override - public String toString() { - return String.format( - "ModbusUnexpectedTransactionIdException(requestTransactionId=%d, responseTransactionId=%d)", requestId, - responseId); - } - - public int getRequestId() { - return requestId; - } - - public int getResponseId() { - return responseId; - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/AggregateStopWatch.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/AggregateStopWatch.java deleted file mode 100644 index 45146decf1674..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/AggregateStopWatch.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import java.util.UUID; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Utility for timing operations - * - * @author Sami Salonen - initial contribution - * - */ -@NonNullByDefault -public class AggregateStopWatch { - /** - * ID associated with this modbus operation - */ - final String operationId; - - /** - * Total operation time - */ - final SimpleStopWatch total = new SimpleStopWatch(); - - /** - * Time for connection related actions - */ - final SimpleStopWatch connection = new SimpleStopWatch(); - - /** - * Time for actual the actual transaction (read/write to slave) - */ - final SimpleStopWatch transaction = new SimpleStopWatch(); - - /** - * Time for calling calling the callback - */ - final SimpleStopWatch callback = new SimpleStopWatch(); - - public AggregateStopWatch() { - this.operationId = UUID.randomUUID().toString(); - } - - /** - * Suspend all running stopwatches of this aggregate - */ - public void suspendAllRunning() { - for (SimpleStopWatch watch : new SimpleStopWatch[] { total, connection, transaction, callback }) { - if (watch.isRunning()) { - watch.suspend(); - } - } - } - - @Override - public String toString() { - return String.format("{total: %d ms, connection: %d, transaction=%d, callback=%d}", total.getTotalTimeMillis(), - connection.getTotalTimeMillis(), transaction.getTotalTimeMillis(), callback.getTotalTimeMillis()); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicPollTask.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicPollTask.java deleted file mode 100644 index 162bda1a7537f..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicPollTask.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * Implementation of {@link PollTask} that differentiates tasks using endpoint, request and callbacks. - * - * Note: Two differentiate poll tasks are considered unequal if their callbacks are unequal. - * - * HashCode and equals should be defined such that two poll tasks considered the same only if their request, - * maxTries, endpoint and callback are the same. - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class BasicPollTask implements PollTask { - - static StandardToStringStyle toStringStyle = new StandardToStringStyle(); - static { - toStringStyle.setUseShortClassName(true); - } - - private ModbusSlaveEndpoint endpoint; - private ModbusReadRequestBlueprint request; - private ModbusReadCallback resultCallback; - private ModbusFailureCallback failureCallback; - - public BasicPollTask(ModbusSlaveEndpoint endpoint, ModbusReadRequestBlueprint request, - ModbusReadCallback resultCallback, ModbusFailureCallback failureCallback) { - this.endpoint = endpoint; - this.request = request; - this.resultCallback = resultCallback; - this.failureCallback = failureCallback; - } - - @Override - public ModbusReadRequestBlueprint getRequest() { - return request; - } - - @Override - public ModbusSlaveEndpoint getEndpoint() { - return endpoint; - } - - @Override - public ModbusReadCallback getResultCallback() { - return resultCallback; - } - - @Override - public ModbusFailureCallback getFailureCallback() { - return failureCallback; - } - - @Override - public int hashCode() { - return new HashCodeBuilder(69, 5).append(request).append(getEndpoint()).append(getResultCallback()) - .append(getFailureCallback()).toHashCode(); - } - - @Override - public String toString() { - return new ToStringBuilder(this, toStringStyle).append("request", request).append("endpoint", endpoint) - .append("resultCallback", getResultCallback()).append("failureCallback", getFailureCallback()) - .toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - return false; - } - BasicPollTask rhs = (BasicPollTask) obj; - return new EqualsBuilder().append(request, rhs.request).append(endpoint, rhs.endpoint) - .append(getResultCallback(), rhs.getResultCallback()) - .append(getFailureCallback(), rhs.getFailureCallback()).isEquals(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicWriteTask.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicWriteTask.java deleted file mode 100644 index 5d4c870070216..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/BasicWriteTask.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.apache.commons.lang.builder.StandardToStringStyle; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusWriteCallback; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.WriteTask; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -/** - * Simple implementation for Modbus write requests - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class BasicWriteTask implements WriteTask { - - private static final StandardToStringStyle TO_STRING_STYLE = new StandardToStringStyle(); - static { - TO_STRING_STYLE.setUseShortClassName(true); - } - - private ModbusSlaveEndpoint endpoint; - private ModbusWriteRequestBlueprint request; - private ModbusWriteCallback resultCallback; - private ModbusFailureCallback failureCallback; - - public BasicWriteTask(ModbusSlaveEndpoint endpoint, ModbusWriteRequestBlueprint request, - ModbusWriteCallback resultCallback, ModbusFailureCallback failureCallback) { - super(); - this.endpoint = endpoint; - this.request = request; - this.resultCallback = resultCallback; - this.failureCallback = failureCallback; - } - - @Override - public ModbusSlaveEndpoint getEndpoint() { - return endpoint; - } - - @Override - public ModbusWriteRequestBlueprint getRequest() { - return request; - } - - @Override - public ModbusWriteCallback getResultCallback() { - return resultCallback; - } - - @Override - public ModbusFailureCallback getFailureCallback() { - return failureCallback; - } - - @Override - public String toString() { - return new ToStringBuilder(this, TO_STRING_STYLE).append("request", request).append("endpoint", endpoint) - .append("resultCallback", resultCallback).append("failureCallback", failureCallback).toString(); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusConnectionPool.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusConnectionPool.java deleted file mode 100644 index e5430d9771d8c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusConnectionPool.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.apache.commons.pool2.KeyedPooledObjectFactory; -import org.apache.commons.pool2.impl.GenericKeyedObjectPool; -import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; - -import net.wimpi.modbus.net.ModbusSlaveConnection; - -/** - * Pool for modbus connections. - * - * Only one connection is allowed to be active at a time. - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusConnectionPool extends GenericKeyedObjectPool { - - public ModbusConnectionPool(KeyedPooledObjectFactory factory) { - super(factory, new ModbusPoolConfig()); - } - - @Override - public void setConfig(@Nullable GenericKeyedObjectPoolConfig conf) { - if (conf == null) { - return; - } else if (!(conf instanceof ModbusPoolConfig)) { - throw new IllegalArgumentException("Only ModbusPoolConfig accepted!"); - } - super.setConfig(conf); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusLibraryWrapper.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusLibraryWrapper.java deleted file mode 100644 index 40fe719c3d456..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusLibraryWrapper.java +++ /dev/null @@ -1,347 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprintVisitor; -import org.openhab.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpointVisitor; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusUDPSlaveEndpoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.wimpi.modbus.io.ModbusSerialTransaction; -import net.wimpi.modbus.io.ModbusTCPTransaction; -import net.wimpi.modbus.io.ModbusTransaction; -import net.wimpi.modbus.io.ModbusUDPTransaction; -import net.wimpi.modbus.msg.ModbusRequest; -import net.wimpi.modbus.msg.ModbusResponse; -import net.wimpi.modbus.msg.ReadCoilsRequest; -import net.wimpi.modbus.msg.ReadCoilsResponse; -import net.wimpi.modbus.msg.ReadInputDiscretesRequest; -import net.wimpi.modbus.msg.ReadInputDiscretesResponse; -import net.wimpi.modbus.msg.ReadInputRegistersRequest; -import net.wimpi.modbus.msg.ReadInputRegistersResponse; -import net.wimpi.modbus.msg.ReadMultipleRegistersRequest; -import net.wimpi.modbus.msg.ReadMultipleRegistersResponse; -import net.wimpi.modbus.msg.WriteCoilRequest; -import net.wimpi.modbus.msg.WriteMultipleCoilsRequest; -import net.wimpi.modbus.msg.WriteMultipleRegistersRequest; -import net.wimpi.modbus.msg.WriteSingleRegisterRequest; -import net.wimpi.modbus.net.ModbusSlaveConnection; -import net.wimpi.modbus.net.SerialConnection; -import net.wimpi.modbus.net.TCPMasterConnection; -import net.wimpi.modbus.net.UDPMasterConnection; -import net.wimpi.modbus.procimg.InputRegister; -import net.wimpi.modbus.procimg.Register; -import net.wimpi.modbus.procimg.SimpleInputRegister; -import net.wimpi.modbus.util.BitVector; - -/** - * Conversion utilities between underlying Modbus library (net.wimpi.modbus) and this transport bundle - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusLibraryWrapper { - - private static Logger getLogger() { - return LoggerFactory.getLogger(ModbusLibraryWrapper.class); - } - - private static BitArray bitArrayFromBitVector(BitVector bitVector, int count) { - boolean[] bits = new boolean[count]; - for (int i = 0; i < count; i++) { - bits[i] = bitVector.getBit(i); - } - return new BitArray(bits); - } - - private static ModbusRegisterArray modbusRegisterArrayFromInputRegisters(InputRegister[] inputRegisters) { - int[] registers = new int[inputRegisters.length]; - for (int i = 0; i < inputRegisters.length; i++) { - registers[i] = inputRegisters[i].getValue(); - } - return new ModbusRegisterArray(registers); - } - - /** - * Convert the general request to Modbus library request object - * - * @param message - * @throws IllegalArgumentException - * 1) in case function code implies coil data but we have registers - * 2) in case function code implies register data but we have coils - * 3) in case there is no data - * 4) in case there is too much data in case of WRITE_COIL or WRITE_SINGLE_REGISTER - * @throws IllegalStateException unexpected function code. Implementation is lacking and this can be considered a - * bug - * @return MODBUS library request matching the write request - */ - public static ModbusRequest createRequest(ModbusWriteRequestBlueprint message) { - // ModbusRequest[] request = new ModbusRequest[1]; - AtomicReference request = new AtomicReference<>(); - AtomicBoolean writeSingle = new AtomicBoolean(false); - switch (message.getFunctionCode()) { - case WRITE_COIL: - writeSingle.set(true); - // fall-through on purpose - case WRITE_MULTIPLE_COILS: - message.accept(new ModbusWriteRequestBlueprintVisitor() { - - @Override - public void visit(ModbusWriteRegisterRequestBlueprint blueprint) { - throw new IllegalArgumentException(); - } - - @Override - public void visit(ModbusWriteCoilRequestBlueprint blueprint) { - BitArray coils = blueprint.getCoils(); - if (coils.size() == 0) { - throw new IllegalArgumentException("Must provide at least one coil"); - } - if (writeSingle.get()) { - if (coils.size() != 1) { - throw new IllegalArgumentException("Must provide single coil with WRITE_COIL"); - } - request.set(new WriteCoilRequest(message.getReference(), coils.getBit(0))); - } else { - request.set(new WriteMultipleCoilsRequest(message.getReference(), - ModbusLibraryWrapper.convertBits(coils))); - } - } - }); - break; - case WRITE_SINGLE_REGISTER: - writeSingle.set(true); - // fall-through on purpose - case WRITE_MULTIPLE_REGISTERS: - message.accept(new ModbusWriteRequestBlueprintVisitor() { - - @Override - public void visit(ModbusWriteRegisterRequestBlueprint blueprint) { - Register[] registers = ModbusLibraryWrapper.convertRegisters(blueprint.getRegisters()); - if (registers.length == 0) { - throw new IllegalArgumentException("Must provide at least one register"); - } - if (writeSingle.get()) { - if (blueprint.getRegisters().size() != 1) { - throw new IllegalArgumentException( - "Must provide single register with WRITE_SINGLE_REGISTER"); - } - request.set(new WriteSingleRegisterRequest(message.getReference(), registers[0])); - } else { - request.set(new WriteMultipleRegistersRequest(message.getReference(), registers)); - } - } - - @Override - public void visit(ModbusWriteCoilRequestBlueprint blueprint) { - throw new IllegalArgumentException(); - } - }); - break; - default: - getLogger().error("Unexpected function code {}", message.getFunctionCode()); - throw new IllegalStateException( - String.format("Unexpected function code %s", message.getFunctionCode())); - } - ModbusRequest modbusRequest = request.get(); - modbusRequest.setUnitID(message.getUnitID()); - modbusRequest.setProtocolID(message.getProtocolID()); - return modbusRequest; - } - - /** - * Create a fresh transaction for the given endpoint and connection - * - * The retries of the transaction will be disabled. - * - * @param endpoint - * @param connection - * @return - */ - public static ModbusTransaction createTransactionForEndpoint(ModbusSlaveEndpoint endpoint, - ModbusSlaveConnection connection) { - ModbusTransaction transaction = endpoint.accept(new ModbusSlaveEndpointVisitor() { - - @Override - public @NonNull ModbusTransaction visit(ModbusTCPSlaveEndpoint modbusIPSlavePoolingKey) { - ModbusTCPTransaction transaction = new ModbusTCPTransaction(); - transaction.setReconnecting(false); - return transaction; - } - - @Override - public @NonNull ModbusTransaction visit(ModbusSerialSlaveEndpoint modbusSerialSlavePoolingKey) { - return new ModbusSerialTransaction(); - } - - @Override - public @NonNull ModbusTransaction visit(ModbusUDPSlaveEndpoint modbusUDPSlavePoolingKey) { - return new ModbusUDPTransaction(); - } - }); - // We disable modbus library retries and handle in the Manager implementation - transaction.setRetries(0); - transaction.setRetryDelayMillis(0); - if (transaction instanceof ModbusSerialTransaction) { - ((ModbusSerialTransaction) transaction).setSerialConnection((SerialConnection) connection); - } else if (transaction instanceof ModbusUDPTransaction) { - ((ModbusUDPTransaction) transaction).setTerminal(((UDPMasterConnection) connection).getTerminal()); - } else if (transaction instanceof ModbusTCPTransaction) { - ((ModbusTCPTransaction) transaction).setConnection((TCPMasterConnection) connection); - } else { - throw new IllegalStateException(); - } - return transaction; - } - - /** - * Create fresh request corresponding to {@link ModbusReadRequestBlueprint} - * - * @param message - * @return - */ - public static ModbusRequest createRequest(ModbusReadRequestBlueprint message) { - ModbusRequest request; - if (message.getFunctionCode() == ModbusReadFunctionCode.READ_COILS) { - request = new ReadCoilsRequest(message.getReference(), message.getDataLength()); - } else if (message.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_DISCRETES) { - request = new ReadInputDiscretesRequest(message.getReference(), message.getDataLength()); - } else if (message.getFunctionCode() == ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS) { - request = new ReadMultipleRegistersRequest(message.getReference(), message.getDataLength()); - } else if (message.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_REGISTERS) { - request = new ReadInputRegistersRequest(message.getReference(), message.getDataLength()); - } else { - throw new IllegalArgumentException(String.format("Unexpected function code %s", message.getFunctionCode())); - } - request.setUnitID(message.getUnitID()); - request.setProtocolID(message.getProtocolID()); - - return request; - } - - /** - * Convert {@link BitArray} to {@link BitVector} - * - * @param bits - * @return - */ - public static BitVector convertBits(BitArray bits) { - BitVector bitVector = new BitVector(bits.size()); - IntStream.range(0, bits.size()).forEach(i -> bitVector.setBit(i, bits.getBit(i))); - return bitVector; - } - - /** - * Convert {@link ModbusRegisterArray} to array of {@link Register} - * - * @param bits - * @return - */ - public static Register[] convertRegisters(ModbusRegisterArray arr) { - return IntStream.range(0, arr.size()).mapToObj(i -> new SimpleInputRegister(arr.getRegister(i))) - .collect(Collectors.toList()).toArray(new Register[0]); - } - - /** - * Get number of bits/registers/discrete inputs in the request. - * - * - * @param response - * @param request - * @return - */ - public static int getNumberOfItemsInResponse(ModbusResponse response, ModbusReadRequestBlueprint request) { - // jamod library seems to be a bit buggy when it comes number of coils/discrete inputs in the response. Some - // of the methods such as ReadCoilsResponse.getBitCount() are returning wrong values. - // - // This is the reason we use a bit more verbose way to get the number of items in the response. - final int responseCount; - if (request.getFunctionCode() == ModbusReadFunctionCode.READ_COILS) { - responseCount = ((ReadCoilsResponse) response).getCoils().size(); - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_DISCRETES) { - responseCount = ((ReadInputDiscretesResponse) response).getDiscretes().size(); - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS) { - responseCount = ((ReadMultipleRegistersResponse) response).getRegisters().length; - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_REGISTERS) { - responseCount = ((ReadInputRegistersResponse) response).getRegisters().length; - } else { - throw new IllegalArgumentException(String.format("Unexpected function code %s", request.getFunctionCode())); - } - return responseCount; - } - - /** - * Invoke callback with the data received - * - * @param message original request - * @param callback callback for read - * @param response Modbus library response object - */ - public static void invokeCallbackWithResponse(ModbusReadRequestBlueprint request, ModbusReadCallback callback, - ModbusResponse response) { - try { - getLogger().trace("Calling read response callback {} for request {}. Response was {}", callback, request, - response); - // The number of coils/discrete inputs received in response are always in the multiples of 8 - // bits. - // So even if querying 5 bits, you will actually get 8 bits. Here we wrap the data in - // BitArrayWrappingBitVector - // with will validate that the consumer is not accessing the "invalid" bits of the response. - int dataItemsInResponse = getNumberOfItemsInResponse(response, request); - if (request.getFunctionCode() == ModbusReadFunctionCode.READ_COILS) { - BitVector bits = ((ReadCoilsResponse) response).getCoils(); - BitArray payload = bitArrayFromBitVector(bits, Math.min(dataItemsInResponse, request.getDataLength())); - callback.handle(new AsyncModbusReadResult(request, payload)); - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_DISCRETES) { - BitVector bits = ((ReadInputDiscretesResponse) response).getDiscretes(); - BitArray payload = bitArrayFromBitVector(bits, Math.min(dataItemsInResponse, request.getDataLength())); - callback.handle(new AsyncModbusReadResult(request, payload)); - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS) { - ModbusRegisterArray payload = modbusRegisterArrayFromInputRegisters( - ((ReadMultipleRegistersResponse) response).getRegisters()); - callback.handle(new AsyncModbusReadResult(request, payload)); - } else if (request.getFunctionCode() == ModbusReadFunctionCode.READ_INPUT_REGISTERS) { - ModbusRegisterArray payload = modbusRegisterArrayFromInputRegisters( - ((ReadInputRegistersResponse) response).getRegisters()); - callback.handle(new AsyncModbusReadResult(request, payload)); - } else { - throw new IllegalArgumentException( - String.format("Unexpected function code %s", request.getFunctionCode())); - } - } finally { - getLogger().trace("Called read response callback {} for request {}. Response was {}", callback, request, - response); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java deleted file mode 100644 index 4d75f9d080223..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java +++ /dev/null @@ -1,1014 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import javax.imageio.IIOException; - -import org.apache.commons.pool2.KeyedObjectPool; -import org.apache.commons.pool2.SwallowedExceptionListener; -import org.apache.commons.pool2.impl.GenericKeyedObjectPool; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.jetty.util.ConcurrentHashSet; -import org.openhab.core.common.ThreadPoolManager; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusWriteResult; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusManager; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusResultCallback; -import org.openhab.io.transport.modbus.ModbusWriteCallback; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; -import org.openhab.io.transport.modbus.TaskWithEndpoint; -import org.openhab.io.transport.modbus.WriteTask; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpointVisitor; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusUDPSlaveEndpoint; -import org.openhab.io.transport.modbus.exception.ModbusConnectionException; -import org.openhab.io.transport.modbus.exception.ModbusUnexpectedResponseFunctionCodeException; -import org.openhab.io.transport.modbus.exception.ModbusUnexpectedResponseSizeException; -import org.openhab.io.transport.modbus.exception.ModbusUnexpectedTransactionIdException; -import org.openhab.io.transport.modbus.internal.pooling.ModbusSlaveConnectionFactoryImpl; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Deactivate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.wimpi.modbus.Modbus; -import net.wimpi.modbus.ModbusException; -import net.wimpi.modbus.ModbusIOException; -import net.wimpi.modbus.ModbusSlaveException; -import net.wimpi.modbus.io.ModbusTransaction; -import net.wimpi.modbus.msg.ModbusRequest; -import net.wimpi.modbus.msg.ModbusResponse; -import net.wimpi.modbus.net.ModbusSlaveConnection; - -/** - * Main implementation of ModbusManager - * - * We use connection pool to ensure that only single transaction is ongoing per each endpoint. This is especially - * important with serial slaves but practice has shown that even many tcp slaves have limited - * capability to handle many connections at the same time - * - * @author Sami Salonen - Initial contribution - */ -@Component(service = ModbusManager.class, configurationPid = "transport.modbus") -@NonNullByDefault -public class ModbusManagerImpl implements ModbusManager { - - static class PollTaskUnregistered extends Exception { - public PollTaskUnregistered(String msg) { - super(msg); - } - - private static final long serialVersionUID = 6939730579178506885L; - } - - @FunctionalInterface - private interface ModbusOperation { - - /** - * Execute the operation. - * - * All errors should be raised. There should not be any retry mechanism implemented at this level - * - * @param timer aggregate stop watch for performance profiling - * @param task task to execute - * @param connection connection to use - * - * @throws IIOException on generic IO errors - * @throws ModbusException on Modbus protocol errors (e.g. ModbusIOException on I/O, ModbusSlaveException on - * slave exception responses) - * @throws ModbusUnexpectedTransactionIdException when transaction IDs of the request and - * response do not match - * @throws ModbusUnexpectedResponseFunctionCodeException when response function code does not match the request - * (ill-behaving slave) - * @throws ModbusUnexpectedResponseSizeException when data length of the response and request do not match - */ - public void accept(AggregateStopWatch timer, T task, ModbusSlaveConnection connection) - throws ModbusException, IIOException, ModbusUnexpectedTransactionIdException, - ModbusUnexpectedResponseFunctionCodeException, ModbusUnexpectedResponseSizeException; - } - - /** - * Check that transaction id of the response and request match - * - * @param response response from the slave corresponding to request - * @param libRequest modbus request - * @param operationId operation id for logging - * @throws ModbusUnexpectedTransactionIdException when transaction IDs of the request and - * response do not match - */ - private void checkTransactionId(ModbusResponse response, ModbusRequest libRequest, String operationId) - throws ModbusUnexpectedTransactionIdException { - // Compare request and response transaction ID. NOTE: ModbusTransaction.getTransactionID() is static and - // not safe to use - if ((response.getTransactionID() != libRequest.getTransactionID()) && !response.isHeadless()) { - throw new ModbusUnexpectedTransactionIdException(libRequest.getTransactionID(), - response.getTransactionID()); - } - } - - /** - * Check that function code of the response and request match - * - * @param response response from the slave corresponding to request - * @param libRequest modbus request - * @param operationId operation id for logging - * @throws ModbusUnexpectedResponseFunctionCodeException when response function code does not match the request - * (ill-behaving slave) - */ - private void checkFunctionCode(ModbusResponse response, ModbusRequest libRequest, String operationId) - throws ModbusUnexpectedResponseFunctionCodeException { - if ((response.getFunctionCode() != libRequest.getFunctionCode())) { - throw new ModbusUnexpectedResponseFunctionCodeException(libRequest.getTransactionID(), - response.getTransactionID()); - } - } - - /** - * Check that number of bits/registers/discrete inputs is not less than what was requested. - * - * According to modbus protocol, we should get always get always equal amount of registers data back as response. - * With coils and discrete inputs, we can get more since responses are in 8 bit chunks. - * - * However, in no case we expect less items in response. - * - * This is to identify clearly invalid responses which might cause problems downstream when using the data. - * - * @param response response response from the slave corresponding to request - * @param request modbus request - * @param operationId operation id for logging - * @throws ModbusUnexpectedResponseSizeException when data length of the response and request do not match - */ - private void checkResponseSize(ModbusResponse response, ModbusReadRequestBlueprint request, String operationId) - throws ModbusUnexpectedResponseSizeException { - final int responseCount = ModbusLibraryWrapper.getNumberOfItemsInResponse(response, request); - if (responseCount < request.getDataLength()) { - throw new ModbusUnexpectedResponseSizeException(request.getDataLength(), responseCount); - } - } - - /** - * Implementation for the PollTask operation - * - * @author Sami Salonen - Initial contribution - * - */ - private class PollOperation implements ModbusOperation { - @Override - public void accept(AggregateStopWatch timer, PollTask task, ModbusSlaveConnection connection) - throws ModbusException, ModbusUnexpectedTransactionIdException, - ModbusUnexpectedResponseFunctionCodeException, ModbusUnexpectedResponseSizeException { - ModbusSlaveEndpoint endpoint = task.getEndpoint(); - ModbusReadRequestBlueprint request = task.getRequest(); - ModbusReadCallback callback = task.getResultCallback(); - String operationId = timer.operationId; - - ModbusTransaction transaction = ModbusLibraryWrapper.createTransactionForEndpoint(endpoint, connection); - ModbusRequest libRequest = ModbusLibraryWrapper.createRequest(request); - transaction.setRequest(libRequest); - - logger.trace("Going execute transaction with request request (FC={}): {} [operation ID {}]", - request.getFunctionCode(), libRequest.getHexMessage(), operationId); - // Might throw ModbusIOException (I/O error) or ModbusSlaveException (explicit exception response from - // slave) - timer.transaction.timeRunnableWithModbusException(() -> transaction.execute()); - ModbusResponse response = transaction.getResponse(); - logger.trace("Response for read request (FC={}, transaction ID={}): {} [operation ID {}]", - response.getFunctionCode(), response.getTransactionID(), response.getHexMessage(), operationId); - checkTransactionId(response, libRequest, operationId); - checkFunctionCode(response, libRequest, operationId); - checkResponseSize(response, request, operationId); - timer.callback - .timeRunnable(() -> ModbusLibraryWrapper.invokeCallbackWithResponse(request, callback, response)); - } - } - - /** - * Implementation for WriteTask operation - * - * @author Sami Salonen - Initial contribution - * - */ - private class WriteOperation implements ModbusOperation { - @Override - public void accept(AggregateStopWatch timer, WriteTask task, ModbusSlaveConnection connection) - throws ModbusException, ModbusUnexpectedTransactionIdException, - ModbusUnexpectedResponseFunctionCodeException { - ModbusSlaveEndpoint endpoint = task.getEndpoint(); - ModbusWriteRequestBlueprint request = task.getRequest(); - @Nullable - ModbusWriteCallback callback = task.getResultCallback(); - String operationId = timer.operationId; - - ModbusTransaction transaction = ModbusLibraryWrapper.createTransactionForEndpoint(endpoint, connection); - ModbusRequest libRequest = ModbusLibraryWrapper.createRequest(request); - transaction.setRequest(libRequest); - - logger.trace("Going execute transaction with read request (FC={}): {} [operation ID {}]", - request.getFunctionCode(), libRequest.getHexMessage(), operationId); - - // Might throw ModbusIOException (I/O error) or ModbusSlaveException (explicit exception response from - // slave) - timer.transaction.timeRunnableWithModbusException(() -> transaction.execute()); - ModbusResponse response = transaction.getResponse(); - logger.trace("Response for write request (FC={}, transaction ID={}): {} [operation ID {}]", - response.getFunctionCode(), response.getTransactionID(), response.getHexMessage(), operationId); - checkTransactionId(response, libRequest, operationId); - checkFunctionCode(response, libRequest, operationId); - timer.callback.timeRunnable( - () -> invokeCallbackWithResponse(request, callback, new ModbusResponseImpl(response))); - } - } - - private final Logger logger = LoggerFactory.getLogger(ModbusManagerImpl.class); - private final Logger pollMonitorLogger = LoggerFactory - .getLogger(ModbusManagerImpl.class.getName() + ".PollMonitor"); - - /** - * Time to wait between connection passive+borrow, i.e. time to wait between - * transactions - * Default 60ms for TCP slaves, Siemens S7 1212 PLC couldn't handle faster - * requests with default settings. - */ - public static final long DEFAULT_TCP_INTER_TRANSACTION_DELAY_MILLIS = 60; - - /** - * Time to wait between connection passive+borrow, i.e. time to wait between - * transactions - * Default 35ms for Serial slaves, motivation discussed - * here https://community.openhab.org/t/connection-pooling-in-modbus-binding/5246/111?u=ssalonen - */ - public static final long DEFAULT_SERIAL_INTER_TRANSACTION_DELAY_MILLIS = 35; - - /** - * Thread naming for modbus read & write requests. Also used by the monitor thread - */ - private static final String MODBUS_POLLER_THREAD_POOL_NAME = "modbusManagerPollerThreadPool"; - - /** - * Log message with WARN level if the task queues exceed this limit. - * - * If the queues grow too large, it might be an issue with consumer of the ModbusManager. - * - * You can generate large queue by spamming ModbusManager with one-off read or writes (submitOnTimePoll or - * submitOneTimeWrite). - * - * Note that there is no issue registering many regular polls, those do not "queue" the same way. - * - * Presumably slow callbacks can increase queue size with callbackThreadPool - */ - private static final long WARN_QUEUE_SIZE = 500; - private static final long MONITOR_QUEUE_INTERVAL_MILLIS = 10000; - - private final PollOperation pollOperation = new PollOperation(); - private final WriteOperation writeOperation = new WriteOperation(); - - private volatile long lastQueueMonitorLog = -1; - - /** - * We use connection pool to ensure that only single transaction is ongoing per each endpoint. This is especially - * important with serial slaves but practice has shown that even many tcp slaves have limited - * capability to handle many connections at the same time - * - * Relevant discussion at the time of implementation: - * - https://community.openhab.org/t/modbus-connection-problem/6108/ - * - https://community.openhab.org/t/connection-pooling-in-modbus-binding/5246/ - */ - - private volatile @Nullable KeyedObjectPool connectionPool; - private volatile @Nullable ModbusSlaveConnectionFactoryImpl connectionFactory; - private volatile Map> scheduledPollTasks = new ConcurrentHashMap<>(); - /** - * Executor for requests - */ - private volatile @Nullable ScheduledExecutorService scheduledThreadPoolExecutor; - private volatile @Nullable ScheduledFuture monitorFuture; - private volatile Set communicationInterfaces = new ConcurrentHashSet<>(); - - private void constructConnectionPool() { - ModbusSlaveConnectionFactoryImpl connectionFactory = new ModbusSlaveConnectionFactoryImpl(); - connectionFactory.setDefaultPoolConfigurationFactory(endpoint -> { - return endpoint.accept(new ModbusSlaveEndpointVisitor() { - - @Override - public @NonNull EndpointPoolConfiguration visit(ModbusTCPSlaveEndpoint modbusIPSlavePoolingKey) { - EndpointPoolConfiguration endpointPoolConfig = new EndpointPoolConfiguration(); - endpointPoolConfig.setInterTransactionDelayMillis(DEFAULT_TCP_INTER_TRANSACTION_DELAY_MILLIS); - endpointPoolConfig.setConnectMaxTries(Modbus.DEFAULT_RETRIES); - return endpointPoolConfig; - } - - @Override - public @NonNull EndpointPoolConfiguration visit(ModbusSerialSlaveEndpoint modbusSerialSlavePoolingKey) { - EndpointPoolConfiguration endpointPoolConfig = new EndpointPoolConfiguration(); - // never "disconnect" (close/open serial port) serial connection between borrows - endpointPoolConfig.setReconnectAfterMillis(-1); - endpointPoolConfig.setInterTransactionDelayMillis(DEFAULT_SERIAL_INTER_TRANSACTION_DELAY_MILLIS); - endpointPoolConfig.setConnectMaxTries(Modbus.DEFAULT_RETRIES); - return endpointPoolConfig; - } - - @Override - public @NonNull EndpointPoolConfiguration visit(ModbusUDPSlaveEndpoint modbusUDPSlavePoolingKey) { - EndpointPoolConfiguration endpointPoolConfig = new EndpointPoolConfiguration(); - endpointPoolConfig.setInterTransactionDelayMillis(DEFAULT_TCP_INTER_TRANSACTION_DELAY_MILLIS); - endpointPoolConfig.setConnectMaxTries(Modbus.DEFAULT_RETRIES); - return endpointPoolConfig; - } - }); - }); - - GenericKeyedObjectPool genericKeyedObjectPool = new ModbusConnectionPool( - connectionFactory); - genericKeyedObjectPool.setSwallowedExceptionListener(new SwallowedExceptionListener() { - - @SuppressWarnings("null") - @Override - public void onSwallowException(@Nullable Exception e) { - LoggerFactory.getLogger(ModbusManagerImpl.class).warn( - "Connection pool swallowed unexpected exception:{} {}", - Optional.ofNullable(e).map(ex -> ex.getClass().getSimpleName()).orElse(""), - Optional.ofNullable(e).map(ex -> ex.getMessage()).orElse(""), e); - } - }); - connectionPool = genericKeyedObjectPool; - this.connectionFactory = connectionFactory; - } - - private Optional borrowConnection(ModbusSlaveEndpoint endpoint) { - Optional connection = Optional.empty(); - KeyedObjectPool pool = connectionPool; - if (pool == null) { - return connection; - } - long start = System.currentTimeMillis(); - try { - connection = Optional.ofNullable(pool.borrowObject(endpoint)); - } catch (Exception e) { - logger.warn("Error getting a new connection for endpoint {}. Error was: {} {}", endpoint, - e.getClass().getName(), e.getMessage()); - } - if (connection.isPresent()) { - ModbusSlaveConnection slaveConnection = connection.get(); - if (!slaveConnection.isConnected()) { - logger.trace( - "Received connection which is unconnected, preventing use by returning connection to pool."); - returnConnection(endpoint, connection); - connection = Optional.empty(); - } - } - logger.trace("borrowing connection (got {}) for endpoint {} took {} ms", connection, endpoint, - System.currentTimeMillis() - start); - return connection; - } - - private void invalidate(ModbusSlaveEndpoint endpoint, Optional connection) { - KeyedObjectPool pool = connectionPool; - if (pool == null) { - return; - } - long start = System.currentTimeMillis(); - connection.ifPresent(con -> { - try { - pool.invalidateObject(endpoint, con); - } catch (Exception e) { - logger.warn("Error invalidating connection in pool for endpoint {}. Error was: {} {}", endpoint, - e.getClass().getName(), e.getMessage(), e); - } - }); - logger.trace("invalidating connection for endpoint {} took {} ms", endpoint, - System.currentTimeMillis() - start); - } - - private void returnConnection(ModbusSlaveEndpoint endpoint, Optional connection) { - KeyedObjectPool pool = connectionPool; - if (pool == null) { - return; - } - long start = System.currentTimeMillis(); - connection.ifPresent(con -> { - try { - pool.returnObject(endpoint, con); - logger.trace("returned connection to pool for endpoint {}", endpoint); - } catch (Exception e) { - logger.warn("Error returning connection to pool for endpoint {}. Error was: {} {}", endpoint, - e.getClass().getName(), e.getMessage(), e); - } - }); - logger.trace("returning connection for endpoint {} took {} ms", endpoint, System.currentTimeMillis() - start); - } - - /** - * Establishes connection to the endpoint specified by the task - * - * In case connection cannot be established, callback is called with {@link ModbusConnectionException} - * - * @param operationId id appened to log messages for identifying the operation - * @param oneOffTask whether this is one-off, or execution of previously scheduled poll - * @param task task representing the read or write operation - * @return {@link ModbusSlaveConnection} to the endpoint as specified by the task, or empty {@link Optional} when - * connection cannot be established - * @throws PollTaskUnregistered - */ - private , T extends TaskWithEndpoint> Optional getConnection( - AggregateStopWatch timer, boolean oneOffTask, @NonNull T task) throws PollTaskUnregistered { - KeyedObjectPool connectionPool = this.connectionPool; - if (connectionPool == null) { - return Optional.empty(); - } - String operationId = timer.operationId; - logger.trace( - "Executing task {} (oneOff={})! Waiting for connection. Idle connections for this endpoint: {}, and active {} [operation ID {}]", - task, oneOffTask, connectionPool.getNumIdle(task.getEndpoint()), - connectionPool.getNumActive(task.getEndpoint()), operationId); - long connectionBorrowStart = System.currentTimeMillis(); - ModbusFailureCallback failureCallback = task.getFailureCallback(); - ModbusSlaveEndpoint endpoint = task.getEndpoint(); - - R request = task.getRequest(); - Optional connection = timer.connection.timeSupplier(() -> borrowConnection(endpoint)); - logger.trace("Executing task {} (oneOff={})! Connection received in {} ms [operation ID {}]", task, oneOffTask, - System.currentTimeMillis() - connectionBorrowStart, operationId); - if (scheduledThreadPoolExecutor == null) { - // manager deactivated - timer.connection.timeRunnable(() -> invalidate(endpoint, connection)); - return Optional.empty(); - } - if (!connection.isPresent()) { - logger.warn("Could not connect to endpoint {} -- aborting request {} [operation ID {}]", endpoint, request, - operationId); - timer.callback.timeRunnable( - () -> invokeCallbackWithError(request, failureCallback, new ModbusConnectionException(endpoint))); - } - return connection; - } - - private void invokeCallbackWithError(R request, ModbusFailureCallback callback, Exception error) { - try { - logger.trace("Calling error response callback {} for request {}. Error was {} {}", callback, request, - error.getClass().getName(), error.getMessage()); - callback.handle(new AsyncModbusFailure(request, error)); - } finally { - logger.trace("Called write response callback {} for request {}. Error was {} {}", callback, request, - error.getClass().getName(), error.getMessage()); - } - } - - private void invokeCallbackWithResponse(ModbusWriteRequestBlueprint request, ModbusWriteCallback callback, - org.openhab.io.transport.modbus.ModbusResponse response) { - try { - logger.trace("Calling write response callback {} for request {}. Response was {}", callback, request, - response); - callback.handle(new AsyncModbusWriteResult(request, response)); - } finally { - logger.trace("Called write response callback {} for request {}. Response was {}", callback, request, - response); - } - } - - private void verifyTaskIsRegistered(PollTask task) throws PollTaskUnregistered { - if (!this.scheduledPollTasks.containsKey(task)) { - String msg = String.format("Poll task %s is unregistered", task); - logger.debug(msg); - throw new PollTaskUnregistered(msg); - } - } - - /** - * Execute operation using a retry mechanism. - * - * This is a helper function for executing read and write operations and handling the exceptions in a common way. - * - * With some connection types, the connection is reseted (disconnected), and new connection is received from the - * pool. This means that potentially other operations queuing for the connection can be executed in-between. - * - * With some other connection types, the operation is retried without reseting the connection type. - * - * @param task - * @param oneOffTask - * @param operation - */ - private , T extends TaskWithEndpoint> void executeOperation( - T task, boolean oneOffTask, ModbusOperation operation) { - AggregateStopWatch timer = new AggregateStopWatch(); - timer.total.resume(); - String operationId = timer.operationId; - - ModbusSlaveConnectionFactoryImpl connectionFactory = this.connectionFactory; - if (connectionFactory == null) { - // deactivated manager - logger.trace("Deactivated manager - aborting operation."); - return; - } - - logTaskQueueInfo(); - R request = task.getRequest(); - ModbusSlaveEndpoint endpoint = task.getEndpoint(); - F failureCallback = task.getFailureCallback(); - int maxTries = task.getMaxTries(); - AtomicReference<@Nullable Exception> lastError = new AtomicReference<>(); - @SuppressWarnings("null") // since cfg in lambda cannot be really null - long retryDelay = Optional.ofNullable(connectionFactory.getEndpointPoolConfiguration(endpoint)) - .map(cfg -> cfg.getInterTransactionDelayMillis()).orElse(0L); - - if (maxTries <= 0) { - throw new IllegalArgumentException("maxTries should be positive"); - } - - Optional connection = Optional.empty(); - try { - logger.trace("Starting new operation with task {}. Trying to get connection [operation ID {}]", task, - operationId); - connection = getConnection(timer, oneOffTask, task); - logger.trace("Operation with task {}. Got a connection {} [operation ID {}]", task, - connection.isPresent() ? "successfully" : "which was unconnected (connection issue)", operationId); - if (!connection.isPresent()) { - // Could not acquire connection, time to abort - // Error logged already, error callback called as well - logger.trace("Initial connection was not successful, aborting. [operation ID {}]", operationId); - return; - } - - if (scheduledThreadPoolExecutor == null) { - logger.debug("Manager has been shut down, aborting proecssing request {} [operation ID {}]", request, - operationId); - return; - } - - int tryIndex = 0; - /** - * last execution is tracked such that the endpoint is not spammed on retry. First retry can be executed - * right away since getConnection ensures enough time has passed since last transaction. More precisely, - * ModbusSlaveConnectionFactoryImpl sleeps on activate() (i.e. before returning connection). - */ - @Nullable - Long lastTryMillis = null; - while (tryIndex < maxTries) { - logger.trace("Try {} out of {} [operation ID {}]", tryIndex + 1, maxTries, operationId); - if (!connection.isPresent()) { - // Connection was likely reseted with previous try, and connection was not successfully - // re-established. Error has been logged, time to abort. - logger.trace("Try {} out of {}. Connection was not successful, aborting. [operation ID {}]", - tryIndex + 1, maxTries, operationId); - return; - } - if (Thread.interrupted()) { - logger.warn("Thread interrupted. Aborting operation [operation ID {}]", operationId); - return; - } - // Check poll task is still registered (this is all asynchronous) - if (!oneOffTask && task instanceof PollTask) { - verifyTaskIsRegistered((PollTask) task); - } - // Let's ensure that enough time is between the retries - logger.trace( - "Ensuring that enough time passes before retrying again. Sleeping if necessary [operation ID {}]", - operationId); - long slept = ModbusSlaveConnectionFactoryImpl.waitAtleast(lastTryMillis, retryDelay); - logger.trace("Sleep ended, slept {} [operation ID {}]", slept, operationId); - - boolean willRetry = false; - try { - tryIndex++; - willRetry = tryIndex < maxTries; - operation.accept(timer, task, connection.get()); - lastError.set(null); - break; - } catch (IOException e) { - lastError.set(new ModbusSlaveIOExceptionImpl(e)); - // IO exception occurred, we re-establish new connection hoping it would fix the issue (e.g. - // broken pipe on write) - if (willRetry) { - logger.warn( - "Try {} out of {} failed when executing request ({}). Will try again soon. Error was I/O error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, maxTries, request, e.getClass().getName(), e.getMessage(), operationId); - } else { - logger.error( - "Last try {} failed when executing request ({}). Aborting. Error was I/O error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, request, e.getClass().getName(), e.getMessage(), operationId); - } - // Invalidate connection, and empty (so that new connection is acquired before new retry) - timer.connection.timeConsumer(c -> invalidate(endpoint, c), connection); - connection = Optional.empty(); - continue; - } catch (ModbusIOException e) { - lastError.set(new ModbusSlaveIOExceptionImpl(e)); - // IO exception occurred, we re-establish new connection hoping it would fix the issue (e.g. - // broken pipe on write) - if (willRetry) { - logger.warn( - "Try {} out of {} failed when executing request ({}). Will try again soon. Error was I/O error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, maxTries, request, e.getClass().getName(), e.getMessage(), operationId); - } else { - logger.error( - "Last try {} failed when executing request ({}). Aborting. Error was I/O error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, request, e.getClass().getName(), e.getMessage(), operationId); - } - // Invalidate connection, and empty (so that new connection is acquired before new retry) - timer.connection.timeConsumer(c -> invalidate(endpoint, c), connection); - connection = Optional.empty(); - continue; - } catch (ModbusSlaveException e) { - lastError.set(new ModbusSlaveErrorResponseExceptionImpl(e)); - // Slave returned explicit error response, no reason to re-establish new connection - if (willRetry) { - logger.warn( - "Try {} out of {} failed when executing request ({}). Will try again soon. Error was: {} {} [operation ID {}]", - tryIndex, maxTries, request, e.getClass().getName(), e.getMessage(), operationId); - } else { - logger.error( - "Last try {} failed when executing request ({}). Aborting. Error was: {} {} [operation ID {}]", - tryIndex, request, e.getClass().getName(), e.getMessage(), operationId); - } - continue; - } catch (ModbusUnexpectedTransactionIdException | ModbusUnexpectedResponseFunctionCodeException - | ModbusUnexpectedResponseSizeException e) { - lastError.set(e); - // transaction error details already logged - if (willRetry) { - logger.warn( - "Try {} out of {} failed when executing request ({}). Will try again soon. The response did not match the request. Reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, maxTries, request, e.getClass().getName(), e.getMessage(), operationId); - } else { - logger.error( - "Last try {} failed when executing request ({}). Aborting. The response did not match the request. Reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, request, e.getClass().getName(), e.getMessage(), operationId); - } - // Invalidate connection, and empty (so that new connection is acquired before new retry) - timer.connection.timeConsumer(c -> invalidate(endpoint, c), connection); - connection = Optional.empty(); - continue; - } catch (ModbusException e) { - lastError.set(e); - // Some other (unexpected) exception occurred - if (willRetry) { - logger.warn( - "Try {} out of {} failed when executing request ({}). Will try again soon. Error was unexpected error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, maxTries, request, e.getClass().getName(), e.getMessage(), operationId, e); - } else { - logger.error( - "Last try {} failed when executing request ({}). Aborting. Error was unexpected error, so reseting the connection. Error details: {} {} [operation ID {}]", - tryIndex, request, e.getClass().getName(), e.getMessage(), operationId, e); - } - // Invalidate connection, and empty (so that new connection is acquired before new retry) - timer.connection.timeConsumer(c -> invalidate(endpoint, c), connection); - connection = Optional.empty(); - continue; - } finally { - lastTryMillis = System.currentTimeMillis(); - // Connection was reseted in error handling and needs to be reconnected. - // Try to re-establish connection. - if (willRetry && !connection.isPresent()) { - connection = getConnection(timer, oneOffTask, task); - } - } - } - Exception exception = lastError.get(); - if (exception != null) { - // All retries failed with some error - timer.callback.timeRunnable(() -> { - invokeCallbackWithError(request, failureCallback, exception); - }); - } - } catch (PollTaskUnregistered e) { - logger.warn("Poll task was unregistered -- not executing/proceeding with the poll: {} [operation ID {}]", - e.getMessage(), operationId); - return; - } catch (InterruptedException e) { - logger.warn("Poll task was canceled -- not executing/proceeding with the poll: {} [operation ID {}]", - e.getMessage(), operationId); - // Invalidate connection, and empty (so that new connection is acquired before new retry) - timer.connection.timeConsumer(c -> invalidate(endpoint, c), connection); - connection = Optional.empty(); - } finally { - timer.connection.timeConsumer(c -> returnConnection(endpoint, c), connection); - logger.trace("Connection was returned to the pool, ending operation [operation ID {}]", operationId); - timer.suspendAllRunning(); - logger.debug("Modbus operation ended, timing info: {} [operation ID {}]", timer, operationId); - } - } - - private class ModbusCommunicationInterfaceImpl implements ModbusCommunicationInterface { - - private volatile ModbusSlaveEndpoint endpoint; - private volatile Set pollTasksRegisteredByThisCommInterface = new ConcurrentHashSet<>(); - private volatile boolean closed; - private @Nullable EndpointPoolConfiguration configuration; - - @SuppressWarnings("null") - public ModbusCommunicationInterfaceImpl(ModbusSlaveEndpoint endpoint, - @Nullable EndpointPoolConfiguration configuration) { - this.endpoint = endpoint; - this.configuration = configuration; - connectionFactory.setEndpointPoolConfiguration(endpoint, configuration); - } - - @Override - public Future submitOneTimePoll(ModbusReadRequestBlueprint request, ModbusReadCallback resultCallback, - ModbusFailureCallback failureCallback) { - if (closed) { - throw new IllegalStateException("Communication interface is closed already!"); - } - ScheduledExecutorService executor = scheduledThreadPoolExecutor; - Objects.requireNonNull(executor, "Not activated!"); - long scheduleTime = System.currentTimeMillis(); - BasicPollTask task = new BasicPollTask(endpoint, request, resultCallback, failureCallback); - logger.debug("Scheduling one-off poll task {}", task); - Future future = executor.submit(() -> { - long millisInThreadPoolWaiting = System.currentTimeMillis() - scheduleTime; - logger.debug("Will now execute one-off poll task {}, waited in thread pool for {}", task, - millisInThreadPoolWaiting); - executeOperation(task, true, pollOperation); - }); - return future; - } - - @Override - public PollTask registerRegularPoll(ModbusReadRequestBlueprint request, long pollPeriodMillis, - long initialDelayMillis, ModbusReadCallback resultCallback, - ModbusFailureCallback failureCallback) { - synchronized (ModbusManagerImpl.this) { - if (closed) { - throw new IllegalStateException("Communication interface is closed already!"); - } - ScheduledExecutorService executor = scheduledThreadPoolExecutor; - Objects.requireNonNull(executor, "Not activated!"); - BasicPollTask task = new BasicPollTask(endpoint, request, resultCallback, failureCallback); - logger.trace("Registering poll task {} with period {} using initial delay {}", task, pollPeriodMillis, - initialDelayMillis); - if (scheduledPollTasks.containsKey(task)) { - logger.trace("Unregistering previous poll task (possibly with different period)"); - unregisterRegularPoll(task); - } - ScheduledFuture future = executor.scheduleWithFixedDelay(() -> { - long started = System.currentTimeMillis(); - logger.debug("Executing scheduled ({}ms) poll task {}. Current millis: {}", pollPeriodMillis, task, - started); - try { - executeOperation(task, false, pollOperation); - } catch (RuntimeException e) { - // We want to catch all unexpected exceptions since all unhandled exceptions make - // ScheduledExecutorService halt the polling. It is better to print out the exception, and try - // again - // (on next poll cycle) - logger.warn( - "Execution of scheduled ({}ms) poll task {} failed unexpectedly. Ignoring exception, polling again according to poll interval.", - pollPeriodMillis, task, e); - } - long finished = System.currentTimeMillis(); - logger.debug( - "Execution of scheduled ({}ms) poll task {} finished at {}. Was started at millis: {} (=duration of {} millis)", - pollPeriodMillis, task, finished, started, finished - started); - }, initialDelayMillis, pollPeriodMillis, TimeUnit.MILLISECONDS); - - scheduledPollTasks.put(task, future); - pollTasksRegisteredByThisCommInterface.add(task); - logger.trace("Registered poll task {} with period {} using initial delay {}", task, pollPeriodMillis, - initialDelayMillis); - return task; - } - } - - @SuppressWarnings({ "null", "unused" }) - @Override - public boolean unregisterRegularPoll(PollTask task) { - synchronized (ModbusManagerImpl.this) { - if (closed) { - // Closed already, nothing to unregister - return false; - } - pollTasksRegisteredByThisCommInterface.remove(task); - ModbusSlaveConnectionFactoryImpl localConnectionFactory = connectionFactory; - Objects.requireNonNull(localConnectionFactory, "Not activated!"); - - // cancel poller - @Nullable - ScheduledFuture future = scheduledPollTasks.remove(task); - if (future == null) { - // No such poll task - logger.warn("Caller tried to unregister nonexisting poll task {}", task); - return false; - } - logger.debug("Unregistering regular poll task {} (interrupting if necessary)", task); - future.cancel(true); - logger.debug("Poll task {} canceled", task); - return true; - } - } - - @Override - public Future submitOneTimeWrite(ModbusWriteRequestBlueprint request, ModbusWriteCallback resultCallback, - ModbusFailureCallback failureCallback) { - if (closed) { - throw new IllegalStateException("Communication interface is closed already!"); - } - ScheduledExecutorService localScheduledThreadPoolExecutor = scheduledThreadPoolExecutor; - Objects.requireNonNull(localScheduledThreadPoolExecutor, "Not activated!"); - WriteTask task = new BasicWriteTask(endpoint, request, resultCallback, failureCallback); - long scheduleTime = System.currentTimeMillis(); - logger.debug("Scheduling one-off write task {}", task); - Future future = localScheduledThreadPoolExecutor.submit(() -> { - long millisInThreadPoolWaiting = System.currentTimeMillis() - scheduleTime; - logger.debug("Will now execute one-off write task {}, waited in thread pool for {}", task, - millisInThreadPoolWaiting); - executeOperation(task, true, writeOperation); - }); - return future; - } - - @Override - public void close() throws Exception { - synchronized (ModbusManagerImpl.this) { - if (closed) { - // Closed already, nothing to unregister - return; - } - // Iterate over all tasks registered by this communication interface, and unregister those - // We copy pollTasksRegisteredByThisCommInterface temporarily so that unregisterRegularPoll can - // remove entries from pollTasksRegisteredByThisCommInterface - Iterable tasksToUnregister = new LinkedList<>(pollTasksRegisteredByThisCommInterface); - for (PollTask task : tasksToUnregister) { - unregisterRegularPoll(task); - } - unregisterCommunicationInterface(this); - closed = true; - } - } - - @Override - public ModbusSlaveEndpoint getEndpoint() { - return endpoint; - } - } - - @Override - public ModbusCommunicationInterface newModbusCommunicationInterface(ModbusSlaveEndpoint endpoint, - @Nullable EndpointPoolConfiguration configuration) throws IllegalArgumentException { - boolean openCommFoundWithSameEndpointDifferentConfig = communicationInterfaces.stream() - .filter(comm -> comm.endpoint.equals(endpoint)) - .anyMatch(comm -> comm.configuration != null && !comm.configuration.equals(configuration)); - if (openCommFoundWithSameEndpointDifferentConfig) { - throw new IllegalArgumentException( - "Communication interface is already open with different configuration to this same endpoint"); - } - - ModbusCommunicationInterfaceImpl comm = new ModbusCommunicationInterfaceImpl(endpoint, configuration); - communicationInterfaces.add(comm); - return comm; - } - - @Override - public @Nullable EndpointPoolConfiguration getEndpointPoolConfiguration(ModbusSlaveEndpoint endpoint) { - Objects.requireNonNull(connectionFactory, "Not activated!"); - return connectionFactory.getEndpointPoolConfiguration(endpoint); - } - - private void unregisterCommunicationInterface(ModbusCommunicationInterface commInterface) { - communicationInterfaces.remove(commInterface); - maybeCloseConnections(commInterface.getEndpoint()); - } - - private void maybeCloseConnections(ModbusSlaveEndpoint endpoint) { - boolean lastCommWithThisEndpointWasRemoved = communicationInterfaces.stream() - .filter(comm -> comm.endpoint.equals(endpoint)).count() == 0L; - if (lastCommWithThisEndpointWasRemoved) { - // Since last communication interface pointing to this endpoint was closed, we can clean up resources - // and disconnect connections. - - // Make sure connections to this endpoint are closed when they are returned to pool (which - // is usually pretty soon as transactions should be relatively short-lived) - ModbusSlaveConnectionFactoryImpl localConnectionFactory = connectionFactory; - if (localConnectionFactory != null) { - localConnectionFactory.disconnectOnReturn(endpoint, System.currentTimeMillis()); - try { - // Close all idle connections as well (they will be reconnected if necessary on borrow) - if (connectionPool != null) { - connectionPool.clear(endpoint); - } - } catch (Exception e) { - logger.warn("Could not clear endpoint {}. Stack trace follows", endpoint, e); - } - } - } - } - - @Activate - protected void activate(Map configProperties) { - synchronized (this) { - logger.info("Modbus manager activated"); - if (connectionPool == null) { - constructConnectionPool(); - } - ScheduledExecutorService scheduledThreadPoolExecutor = this.scheduledThreadPoolExecutor; - if (scheduledThreadPoolExecutor == null) { - this.scheduledThreadPoolExecutor = scheduledThreadPoolExecutor = ThreadPoolManager - .getScheduledPool(MODBUS_POLLER_THREAD_POOL_NAME); - } - if (scheduledThreadPoolExecutor.isShutdown()) { - logger.warn("Thread pool is shut down! Aborting activation of ModbusMangerImpl"); - throw new IllegalStateException("Thread pool(s) shut down! Aborting activation of ModbusMangerImpl"); - } - monitorFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(this::logTaskQueueInfo, 0, - MONITOR_QUEUE_INTERVAL_MILLIS, TimeUnit.MILLISECONDS); - } - } - - @Deactivate - protected void deactivate() { - synchronized (this) { - KeyedObjectPool connectionPool = this.connectionPool; - if (connectionPool != null) { - - for (ModbusCommunicationInterface commInterface : this.communicationInterfaces) { - try { - commInterface.close(); - } catch (Exception e) { - logger.warn("Error when closing communication interface", e); - } - } - - connectionPool.close(); - this.connectionPool = connectionPool = null; - } - - if (monitorFuture != null) { - monitorFuture.cancel(true); - monitorFuture = null; - } - // Note that it is not allowed to shutdown the executor, since they will be reused when - // when pool is received from ThreadPoolManager is called - scheduledThreadPoolExecutor = null; - connectionFactory = null; - logger.debug("Modbus manager deactivated"); - } - } - - private void logTaskQueueInfo() { - synchronized (pollMonitorLogger) { - ScheduledExecutorService scheduledThreadPoolExecutor = this.scheduledThreadPoolExecutor; - if (scheduledThreadPoolExecutor == null) { - return; - } - // Avoid excessive spamming with queue monitor when many tasks are executed - if (System.currentTimeMillis() - lastQueueMonitorLog < MONITOR_QUEUE_INTERVAL_MILLIS) { - return; - } - lastQueueMonitorLog = System.currentTimeMillis(); - pollMonitorLogger.trace(""); - this.scheduledPollTasks.forEach((task, future) -> { - pollMonitorLogger.trace( - "POLL MONITOR: scheduled poll task. FC: {}, start {}, length {}, done: {}, canceled: {}, delay: {}. Full task {}", - task.getRequest().getFunctionCode(), task.getRequest().getReference(), - task.getRequest().getDataLength(), future.isDone(), future.isCancelled(), - future.getDelay(TimeUnit.MILLISECONDS), task); - }); - if (scheduledThreadPoolExecutor instanceof ThreadPoolExecutor) { - ThreadPoolExecutor executor = ((ThreadPoolExecutor) scheduledThreadPoolExecutor); - pollMonitorLogger.trace( - "POLL MONITOR: scheduledThreadPoolExecutor queue size: {}, remaining space {}. Active threads {}", - executor.getQueue().size(), executor.getQueue().remainingCapacity(), executor.getActiveCount()); - if (executor.getQueue().size() >= WARN_QUEUE_SIZE) { - pollMonitorLogger.warn( - "Many ({}) tasks queued in scheduledThreadPoolExecutor! This might be sign of bad design or bug in the binding code.", - executor.getQueue().size()); - } - } - - pollMonitorLogger.trace(""); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusPoolConfig.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusPoolConfig.java deleted file mode 100644 index 94ee4d27bfe0c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusPoolConfig.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.apache.commons.pool2.impl.DefaultEvictionPolicy; -import org.apache.commons.pool2.impl.EvictionPolicy; -import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.internal.pooling.ModbusSlaveConnectionEvictionPolicy; - -import net.wimpi.modbus.net.ModbusSlaveConnection; - -/** - * Configuration for Modbus connection pool - * - * Default is that - * - there is only one connection per endpoint - * - clients are served "fairly" (first-come-first-serve) - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusPoolConfig extends GenericKeyedObjectPoolConfig { - - @SuppressWarnings("unused") - private EvictionPolicy evictionPolicy = new DefaultEvictionPolicy<>(); - - public ModbusPoolConfig() { - // When the pool is exhausted, multiple calling threads may be simultaneously blocked waiting for instances - // to - // become available. As of pool 1.5, a "fairness" algorithm has been implemented to ensure that threads - // receive - // available instances in request arrival order. - setFairness(true); - - // Limit one connection per endpoint (i.e. same ip:port pair or same serial device). - // If there are multiple read/write requests to process at the same time, block until previous one finishes - setBlockWhenExhausted(true); - setMaxTotalPerKey(1); - - // block infinitely when exhausted - setMaxWaitMillis(-1); - - // Connections are "tested" on return. Effectively, disconnected connections are destroyed when returning on - // pool - // Note that we do not test on borrow -- that would mean blocking situation when connection cannot be - // established. - // Instead, borrowing connection from pool can return unconnected connection. - setTestOnReturn(true); - - // disable JMX - setJmxEnabled(false); - - // Evict idle connections every 10 seconds - setEvictionPolicy(new ModbusSlaveConnectionEvictionPolicy()); - setTimeBetweenEvictionRunsMillis(10000); - // Let eviction re-create ready-to-use idle (=unconnected) connections - // This is to avoid occasional / rare deadlocks seen with pool 2.8.1 & 2.4.3 when - // borrow hangs (waiting indefinitely for idle object to appear in the pool) - // https://github.com/openhab/openhab-addons/issues/8460 - setMinIdlePerKey(1); - } - - @Override - public void setEvictionPolicyClassName(@Nullable String evictionPolicyClassName) { - // Protect against https://issues.apache.org/jira/browse/POOL-338 - // Disallow re-setting eviction policy with class name. Only setEvictionPolicy allowed - throw new IllegalStateException("setEvictionPolicyClassName disallowed! Will fail in OSGI"); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusResponseImpl.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusResponseImpl.java deleted file mode 100644 index 13a853366a7c5..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusResponseImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.ModbusResponse; - -import net.wimpi.modbus.msg.ModbusMessage; - -/** - * Basic implementation of {@link ModbusResponse} - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ModbusResponseImpl implements ModbusResponse { - - private int responseFunctionCode; - - public ModbusResponseImpl(ModbusMessage response) { - super(); - this.responseFunctionCode = response.getFunctionCode(); - } - - @Override - public int getFunctionCode() { - return responseFunctionCode; - } - - @Override - public String toString() { - return String.format("ModbusResponseImpl(responseFC=%d)", responseFunctionCode); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveErrorResponseExceptionImpl.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveErrorResponseExceptionImpl.java deleted file mode 100644 index 505f704c303cf..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveErrorResponseExceptionImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.exception.ModbusSlaveErrorResponseException; - -import net.wimpi.modbus.ModbusSlaveException; - -/** - * Exception for explicit exception responses from Modbus slave - * - * @author Sami Salonen - Initial contribution - * @author Nagy Attila Gabor - added getter for error type - * - */ -@NonNullByDefault -public class ModbusSlaveErrorResponseExceptionImpl extends ModbusSlaveErrorResponseException { - - private static final long serialVersionUID = 6334580162425192133L; - private int type; - - public ModbusSlaveErrorResponseExceptionImpl(ModbusSlaveException e) { - type = e.getType(); - } - - /** - * @return the Modbus exception code that happened - */ - @Override - public int getExceptionCode() { - return type; - } - - @Override - public @Nullable String getMessage() { - return String.format("Slave responsed with error=%d", type); - } - - @Override - public String toString() { - return String.format("ModbusSlaveErrorResponseException(error=%d)", type); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveIOExceptionImpl.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveIOExceptionImpl.java deleted file mode 100644 index 24e8b0c09d75a..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusSlaveIOExceptionImpl.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import java.io.IOException; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.exception.ModbusSlaveIOException; - -import net.wimpi.modbus.ModbusIOException; - -/** - * Exception for all IO errors - * - * @author Sami Salonen - Initial contribution - * - */ -@NonNullByDefault -public class ModbusSlaveIOExceptionImpl extends ModbusSlaveIOException { - - private static final long serialVersionUID = -8910463902857643468L; - private Exception error; - - public ModbusSlaveIOExceptionImpl(ModbusIOException e) { - this.error = e; - } - - public ModbusSlaveIOExceptionImpl(IOException e) { - this.error = e; - } - - @Override - public @Nullable String getMessage() { - return String.format("Modbus IO Error with cause=%s, EOF=%s, message='%s', cause2=%s", - error.getClass().getSimpleName(), - error instanceof ModbusIOException ? ((ModbusIOException) error).isEOF() : "?", error.getMessage(), - error.getCause()); - } - - @Override - public String toString() { - return String.format("ModbusSlaveIOException(cause=%s, EOF=%s, message='%s', cause2=%s)", - error.getClass().getSimpleName(), - error instanceof ModbusIOException ? ((ModbusIOException) error).isEOF() : "?", error.getMessage(), - error.getCause()); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/SimpleStopWatch.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/SimpleStopWatch.java deleted file mode 100644 index 6bedf4c81905c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/SimpleStopWatch.java +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.internal.ModbusManagerImpl.PollTaskUnregistered; - -import net.wimpi.modbus.ModbusException; - -/** - * Implementation of simple stop watch. - * - * @author Sami Salonen - initial contribution - * - */ -@NonNullByDefault -public class SimpleStopWatch { - - private volatile long totalMillis; - private volatile long resumed; - - @FunctionalInterface - public abstract interface SupplierWithPollTaskUnregisteredException { - public abstract T get() throws ModbusManagerImpl.PollTaskUnregistered; - } - - @FunctionalInterface - public abstract interface RunnableWithModbusException { - public abstract void run() throws ModbusException; - } - - /** - * Resume or start the stop watch - * - * @throws IllegalStateException if stop watch is running already - */ - public synchronized void resume() { - if (isRunning()) { - throw new IllegalStateException("Cannot suspend a running StopWatch"); - } - resumed = System.currentTimeMillis(); - } - - /** - * Suspend the stop watch - * - * @throws IllegalStateException if stop watch has not been resumed - */ - public synchronized void suspend() { - if (!isRunning()) { - throw new IllegalStateException("Cannot suspend non-running StopWatch"); - } - totalMillis += System.currentTimeMillis() - resumed; - resumed = 0; - } - - /** - * Get total running time of this StopWatch in milliseconds - * - * @return total running time in milliseconds - */ - public synchronized long getTotalTimeMillis() { - return totalMillis; - } - - /** - * Tells whether this StopWatch is now running - * - * @return boolean telling whether this StopWatch is running - */ - public synchronized boolean isRunning() { - return resumed > 0; - } - - /** - * Time single action using this StopWatch - * - * First StopWatch is resumed, then action is applied. Finally the StopWatch is suspended. - * - * @param supplier action to time - * @return return value from supplier - * @throws PollTaskUnregistered when original supplier throws the exception - */ - public R timeSupplierWithPollTaskUnregisteredException(SupplierWithPollTaskUnregisteredException supplier) - throws PollTaskUnregistered { - try { - this.resume(); - return supplier.get(); - } finally { - this.suspend(); - } - } - - /** - * Time single action using this StopWatch - * - * First StopWatch is resumed, then action is applied. Finally the StopWatch is suspended. - * - * @param supplier action to time - * @return return value from supplier - */ - public R timeSupplier(Supplier supplier) { - try { - this.resume(); - return supplier.get(); - } finally { - this.suspend(); - } - } - - /** - * Time single action using this StopWatch - * - * First StopWatch is resumed, then action is applied. Finally the StopWatch is suspended. - * - * @param action action to time - * @throws ModbusException when original action throws the exception - */ - public void timeRunnableWithModbusException(RunnableWithModbusException action) throws ModbusException { - try { - this.resume(); - action.run(); - } finally { - this.suspend(); - } - } - - /** - * Time single action using this StopWatch - * - * First StopWatch is resumed, then action is applied. Finally the StopWatch is suspended. - * - * @param supplier action to time - * @return return value from supplier - */ - public void timeRunnable(Runnable runnable) { - try { - this.resume(); - runnable.run(); - } finally { - this.suspend(); - } - } - - /** - * Time single action using this StopWatch - * - * First StopWatch is resumed, then action is applied. Finally the StopWatch is suspended. - * - * @param consumer action to time - * @return return value from supplier - */ - public void timeConsumer(Consumer consumer, T parameter) { - try { - this.resume(); - consumer.accept(parameter); - } finally { - this.suspend(); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionEvictionPolicy.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionEvictionPolicy.java deleted file mode 100644 index beac2802615c7..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionEvictionPolicy.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal.pooling; - -import org.apache.commons.pool2.PooledObject; -import org.apache.commons.pool2.impl.EvictionConfig; -import org.apache.commons.pool2.impl.EvictionPolicy; -import org.openhab.io.transport.modbus.internal.pooling.ModbusSlaveConnectionFactoryImpl.PooledConnection; - -import net.wimpi.modbus.net.ModbusSlaveConnection; - -/** - * Eviction policy, i.e. policy for deciding when to close idle, unused connections. - * - * Connections are evicted according to {@link PooledConnection} maybeResetConnection method. - * - * @author Sami Salonen - Initial contribution - */ -public class ModbusSlaveConnectionEvictionPolicy implements EvictionPolicy { - - @Override - public boolean evict(EvictionConfig config, PooledObject underTest, int idleCount) { - return ((PooledConnection) underTest).maybeResetConnection("evict"); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactory.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactory.java deleted file mode 100644 index 1f2534529c153..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal.pooling; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpointVisitor; - -import net.wimpi.modbus.net.ModbusSlaveConnection; - -/** - * Factory for ModbusSlaveConnection objects using endpoint definition. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public interface ModbusSlaveConnectionFactory extends ModbusSlaveEndpointVisitor { - -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactoryImpl.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactoryImpl.java deleted file mode 100644 index 04a5d0bb151e2..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactoryImpl.java +++ /dev/null @@ -1,364 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.internal.pooling; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -import org.apache.commons.pool2.BaseKeyedPooledObjectFactory; -import org.apache.commons.pool2.PooledObject; -import org.apache.commons.pool2.impl.DefaultPooledObject; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusIPSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpointVisitor; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusUDPSlaveEndpoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.wimpi.modbus.net.ModbusSlaveConnection; -import net.wimpi.modbus.net.SerialConnection; -import net.wimpi.modbus.net.TCPMasterConnection; -import net.wimpi.modbus.net.UDPMasterConnection; - -/** - * ModbusSlaveConnectionFactoryImpl responsible of the lifecycle of modbus slave connections - * - * The actual pool uses instance of this class to create and destroy connections as-needed. - * - * The overall functionality goes as follow - * - create: create connection object but do not connect it yet - * - destroyObject: close connection and free all resources. Called by the pool when the pool is being closed or the - * object is invalidated. - * - activateObject: prepare connection to be used. In practice, connect if disconnected - * - passivateObject: passivate connection before returning it back to the pool. Currently, passivateObject closes all - * IP-based connections every now and then (reconnectAfterMillis). Serial connections we keep open. - * - wrap: wrap created connection to pooled object wrapper class. It tracks usage statistics and last connection time. - * - * Note that the implementation must be thread safe. - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public class ModbusSlaveConnectionFactoryImpl - extends BaseKeyedPooledObjectFactory { - - class PooledConnection extends DefaultPooledObject { - - private volatile long lastConnected; - private volatile @Nullable ModbusSlaveEndpoint endpoint; - - public PooledConnection(ModbusSlaveConnection object) { - super(object); - } - - public long getLastConnected() { - return lastConnected; - } - - public void setLastConnected(ModbusSlaveEndpoint endpoint, long lastConnected) { - this.endpoint = endpoint; - this.lastConnected = lastConnected; - } - - /** - * - * Reset connection if it is too old or fulfills some of the other criteria - * - * @param activityName ongoing activity calling this method. For logging - * @return whether connection was reseted - */ - public boolean maybeResetConnection(String activityName) { - ModbusSlaveEndpoint localEndpoint = endpoint; - if (localEndpoint == null) { - // We have not connected yet, abort - // Without endpoint we have no age parameters available (endpointPoolConfigs & - // disconnectIfConnectedBefore) - return false; - } - long localLastConnected = lastConnected; - - ModbusSlaveConnection connection = getObject(); - - @Nullable - EndpointPoolConfiguration configuration = endpointPoolConfigs.get(localEndpoint); - long reconnectAfterMillis = configuration == null ? 0 : configuration.getReconnectAfterMillis(); - long connectionAgeMillis = System.currentTimeMillis() - localLastConnected; - long disconnectIfConnectedBeforeMillis = disconnectIfConnectedBefore.getOrDefault(localEndpoint, -1L); - boolean disconnectSinceTooOldConnection = disconnectIfConnectedBeforeMillis < 0L ? false - : localLastConnected <= disconnectIfConnectedBeforeMillis; - boolean shouldBeDisconnected = (reconnectAfterMillis == 0 - || (reconnectAfterMillis > 0 && connectionAgeMillis > reconnectAfterMillis) - || disconnectSinceTooOldConnection); - if (shouldBeDisconnected) { - logger.trace( - "({}) Connection {} (endpoint {}) age {}ms is over the reconnectAfterMillis={}ms limit or has been connection time ({}) is after the \"disconnectBeforeConnectedMillis\"={} -> disconnecting.", - activityName, connection, localEndpoint, connectionAgeMillis, reconnectAfterMillis, - localLastConnected, disconnectIfConnectedBeforeMillis); - connection.resetConnection(); - return true; - } else { - logger.trace( - "({}) Connection {} (endpoint {}) age ({}ms) is below the reconnectAfterMillis ({}ms) limit and connection time ({}) is after the \"disconnectBeforeConnectedMillis\"={}. Keep the connection open.", - activityName, connection, localEndpoint, connectionAgeMillis, reconnectAfterMillis, - localLastConnected, disconnectIfConnectedBeforeMillis); - return false; - } - } - } - - private final Logger logger = LoggerFactory.getLogger(ModbusSlaveConnectionFactoryImpl.class); - private volatile Map endpointPoolConfigs = new ConcurrentHashMap<>(); - private volatile Map lastPassivateMillis = new ConcurrentHashMap<>(); - private volatile Map lastConnectMillis = new ConcurrentHashMap<>(); - private volatile Map disconnectIfConnectedBefore = new ConcurrentHashMap<>(); - private volatile Function defaultPoolConfigurationFactory = endpoint -> null; - - private @Nullable InetAddress getInetAddress(ModbusIPSlaveEndpoint key) { - try { - return InetAddress.getByName(key.getAddress()); - } catch (UnknownHostException e) { - logger.error("KeyedPooledModbusSlaveConnectionFactory: Unknown host: {}. Connection creation failed.", - e.getMessage()); - return null; - } - } - - @Override - public ModbusSlaveConnection create(ModbusSlaveEndpoint endpoint) throws Exception { - return endpoint.accept(new ModbusSlaveEndpointVisitor() { - @Override - public @Nullable ModbusSlaveConnection visit(ModbusSerialSlaveEndpoint modbusSerialSlavePoolingKey) { - SerialConnection connection = new SerialConnection(modbusSerialSlavePoolingKey.getSerialParameters()); - logger.trace("Created connection {} for endpoint {}", connection, modbusSerialSlavePoolingKey); - return connection; - } - - @Override - public @Nullable ModbusSlaveConnection visit(ModbusTCPSlaveEndpoint key) { - InetAddress address = getInetAddress(key); - if (address == null) { - return null; - } - EndpointPoolConfiguration config = getEndpointPoolConfiguration(key); - int connectTimeoutMillis = 0; - if (config != null) { - connectTimeoutMillis = config.getConnectTimeoutMillis(); - } - TCPMasterConnection connection = new TCPMasterConnection(address, key.getPort(), connectTimeoutMillis); - logger.trace("Created connection {} for endpoint {}", connection, key); - return connection; - } - - @Override - public @Nullable ModbusSlaveConnection visit(ModbusUDPSlaveEndpoint key) { - InetAddress address = getInetAddress(key); - if (address == null) { - return null; - } - UDPMasterConnection connection = new UDPMasterConnection(address, key.getPort()); - logger.trace("Created connection {} for endpoint {}", connection, key); - return connection; - } - }); - } - - @Override - public PooledObject wrap(ModbusSlaveConnection connection) { - return new PooledConnection(connection); - } - - @Override - public void destroyObject(ModbusSlaveEndpoint endpoint, @Nullable PooledObject obj) { - if (obj == null) { - return; - } - logger.trace("destroyObject for connection {} and endpoint {} -> closing the connection", obj.getObject(), - endpoint); - obj.getObject().resetConnection(); - } - - @Override - public void activateObject(ModbusSlaveEndpoint endpoint, @Nullable PooledObject obj) - throws Exception { - if (obj == null) { - return; - } - ModbusSlaveConnection connection = obj.getObject(); - try { - @Nullable - EndpointPoolConfiguration config = getEndpointPoolConfiguration(endpoint); - if (!connection.isConnected()) { - tryConnect(endpoint, obj, connection, config); - } - - if (config != null) { - long waited = waitAtleast(lastPassivateMillis.get(endpoint), config.getInterTransactionDelayMillis()); - logger.trace( - "Waited {}ms (interTransactionDelayMillis {}ms) before giving returning connection {} for endpoint {}, to ensure delay between transactions.", - waited, config.getInterTransactionDelayMillis(), obj.getObject(), endpoint); - } - } catch (InterruptedException e) { - // Someone wants to cancel us, reset the connection and abort - if (connection.isConnected()) { - connection.resetConnection(); - } - } catch (Exception e) { - logger.error("Error connecting connection {} for endpoint {}: {}", obj.getObject(), endpoint, - e.getMessage()); - } - } - - @Override - public void passivateObject(ModbusSlaveEndpoint endpoint, @Nullable PooledObject obj) { - if (obj == null) { - return; - } - ModbusSlaveConnection connection = obj.getObject(); - logger.trace("Passivating connection {} for endpoint {}...", connection, endpoint); - lastPassivateMillis.put(endpoint, System.currentTimeMillis()); - ((PooledConnection) obj).maybeResetConnection("passivate"); - logger.trace("...Passivated connection {} for endpoint {}", obj.getObject(), endpoint); - } - - @Override - public boolean validateObject(ModbusSlaveEndpoint key, @Nullable PooledObject p) { - boolean valid = p != null && p.getObject().isConnected(); - logger.trace("Validating endpoint {} connection {} -> {}", key, p.getObject(), valid); - return valid; - } - - /** - * Configure general connection settings with a given endpoint - * - * @param endpoint endpoint to configure - * @param configuration configuration for the endpoint. Use null to reset the configuration to default settings. - */ - public void setEndpointPoolConfiguration(ModbusSlaveEndpoint endpoint, @Nullable EndpointPoolConfiguration config) { - if (config == null) { - endpointPoolConfigs.remove(endpoint); - } else { - endpointPoolConfigs.put(endpoint, config); - } - } - - /** - * Get general configuration settings applied to a given endpoint - * - * Note that default configuration settings are returned in case the endpoint has not been configured. - * - * @param endpoint endpoint to query - * @return general connection settings of the given endpoint - */ - @SuppressWarnings("null") - public @Nullable EndpointPoolConfiguration getEndpointPoolConfiguration(ModbusSlaveEndpoint endpoint) { - @Nullable - EndpointPoolConfiguration config = endpointPoolConfigs.computeIfAbsent(endpoint, - defaultPoolConfigurationFactory); - return config; - } - - /** - * Set default factory for {@link EndpointPoolConfiguration} - * - * @param defaultPoolConfigurationFactory function providing defaults for a given endpoint - */ - public void setDefaultPoolConfigurationFactory( - Function defaultPoolConfigurationFactory) { - this.defaultPoolConfigurationFactory = defaultPoolConfigurationFactory; - } - - private void tryConnect(ModbusSlaveEndpoint endpoint, PooledObject obj, - ModbusSlaveConnection connection, @Nullable EndpointPoolConfiguration config) throws Exception { - if (connection.isConnected()) { - return; - } - int tryIndex = 0; - Long lastConnect = lastConnectMillis.get(endpoint); - int maxTries = config == null ? 1 : config.getConnectMaxTries(); - do { - try { - if (config != null) { - long waited = waitAtleast(lastConnect, - Math.max(config.getInterConnectDelayMillis(), config.getInterTransactionDelayMillis())); - if (waited > 0) { - logger.trace( - "Waited {}ms (interConnectDelayMillis {}ms, interTransactionDelayMillis {}ms) before " - + "connecting disconnected connection {} for endpoint {}, to allow delay " - + "between connections re-connects", - waited, config.getInterConnectDelayMillis(), config.getInterTransactionDelayMillis(), - obj.getObject(), endpoint); - } - } - connection.connect(); - long curTime = System.currentTimeMillis(); - ((PooledConnection) obj).setLastConnected(endpoint, curTime); - lastConnectMillis.put(endpoint, curTime); - break; - } catch (InterruptedException e) { - logger.error("connect try {}/{} error: {}. Aborting since interrupted. Connection {}. Endpoint {}.", - tryIndex, maxTries, e.getMessage(), connection, endpoint); - throw e; - } catch (Exception e) { - tryIndex++; - logger.error("connect try {}/{} error: {}. Connection {}. Endpoint {}", tryIndex, maxTries, - e.getMessage(), connection, endpoint); - if (tryIndex >= maxTries) { - logger.error("re-connect reached max tries {}, throwing last error: {}. Connection {}. Endpoint {}", - maxTries, e.getMessage(), connection, endpoint); - throw e; - } - lastConnect = System.currentTimeMillis(); - } - } while (true); - } - - /** - * Sleep until waitMillis has passed from lastOperation - * - * @param lastOperation last time operation was executed, or null if it has not been executed - * @param waitMillis - * @return milliseconds slept - * @throws InterruptedException - */ - public static long waitAtleast(@Nullable Long lastOperation, long waitMillis) throws InterruptedException { - if (lastOperation == null) { - return 0; - } - long millisSinceLast = System.currentTimeMillis() - lastOperation; - long millisToWaitStill = Math.min(waitMillis, Math.max(0, waitMillis - millisSinceLast)); - try { - Thread.sleep(millisToWaitStill); - } catch (InterruptedException e) { - LoggerFactory.getLogger(ModbusSlaveConnectionFactoryImpl.class).debug("wait interrupted", e); - throw e; - } - return millisToWaitStill; - } - - /** - * Disconnect returning connections which have been connected before certain time - * - * @param disconnectBeforeConnectedMillis disconnected connections that have been connected before this time - */ - public void disconnectOnReturn(ModbusSlaveEndpoint endpoint, long disconnectBeforeConnectedMillis) { - disconnectIfConnectedBefore.put(endpoint, disconnectBeforeConnectedMillis); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/json/WriteRequestJsonUtilities.java b/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/json/WriteRequestJsonUtilities.java deleted file mode 100644 index f0c9eab5627a1..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/json/WriteRequestJsonUtilities.java +++ /dev/null @@ -1,217 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.json; - -import java.util.Collection; -import java.util.Deque; -import java.util.LinkedList; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.lang.NotImplementedException; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusConstants; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -/** - * Utilities for converting JSON to {@link ModbusWriteRequestBlueprint} - * - * - * @author Sami Salonen - Initial contribution - */ -@NonNullByDefault -public final class WriteRequestJsonUtilities { - /** - * Constant for the function code key in the JSON - */ - public static final String JSON_FUNCTION_CODE = "functionCode"; - /** - * Constant for the write address key in the JSON - */ - public static final String JSON_ADDRESS = "address"; - /** - * Constant for the value key in the JSON - */ - public static final String JSON_VALUE = "value"; - /** - * Constant for the maxTries key in the JSON - */ - public static final String JSON_MAX_TRIES = "maxTries"; - - /** - * Default maxTries when it has not been specified - */ - public static final int DEFAULT_MAX_TRIES = 3; - - private static final JsonParser PARSER = new JsonParser(); - - private WriteRequestJsonUtilities() { - throw new NotImplementedException(); - } - - /** - * Parse JSON string to collection of {@link ModbusWriteRequestBlueprint} - * - * JSON string should represent a JSON array, with JSON objects. Each JSON object represents a write request. The - * JSON object must have the following keys - * - functionCode: numeric function code - * - address: reference or start address of the write - * - value: array of data to be written. Use zero and one when writing coils. With registers, each number - * corresponds to register's 16 bit data. - * - maxTries: number of tries with the write in case of errors - * - * - * @param unitId unit id for the constructed {@link ModbusWriteRequestBlueprint} - * @param jsonString json to be parsed in string format - * @return collection of {@link ModbusWriteRequestBlueprint} representing the json - * @throws IllegalArgumentException in case of unexpected function codes, or too large payload exceeding modbus - * protocol specification - * @throws IllegalStateException in case of parsing errors and unexpected json structure - * - * @see WriteRequestJsonUtilities.JSON_FUNCTION_CODE - * @see WriteRequestJsonUtilities.JSON_ADDRESS - * @see WriteRequestJsonUtilities.JSON_VALUE - * @see WriteRequestJsonUtilities.JSON_MAX_TRIES - */ - public static Collection fromJson(int unitId, String jsonString) { - JsonArray jsonArray = PARSER.parse(jsonString).getAsJsonArray(); - if (jsonArray.size() == 0) { - return new LinkedList<>(); - } - Deque writes = new LinkedList<>(); - jsonArray.forEach(writeElem -> { - writes.add(constructBluerint(unitId, writeElem)); - }); - return writes; - } - - private static ModbusWriteRequestBlueprint constructBluerint(int unitId, JsonElement arrayElement) { - final JsonObject writeObject; - try { - writeObject = arrayElement.getAsJsonObject(); - } catch (IllegalStateException e) { - throw new IllegalStateException("JSON array contained something else than a JSON object!", e); - } - @Nullable - JsonElement functionCode = writeObject.get(JSON_FUNCTION_CODE); - @Nullable - JsonElement address = writeObject.get(JSON_ADDRESS); - @Nullable - JsonElement maxTries = writeObject.get(JSON_MAX_TRIES); - @Nullable - JsonArray valuesElem; - - try { - valuesElem = writeObject.get(JSON_VALUE).getAsJsonArray(); - } catch (IllegalStateException e) { - throw new IllegalStateException(String.format("JSON object '%s' is not an JSON array!", JSON_VALUE), e); - } - return constructBluerint(unitId, functionCode, address, maxTries, valuesElem); - } - - private static ModbusWriteRequestBlueprint constructBluerint(int unitId, @Nullable JsonElement functionCodeElem, - @Nullable JsonElement addressElem, @Nullable JsonElement maxTriesElem, @Nullable JsonArray valuesElem) { - int functionCodeNumeric; - if (functionCodeElem == null || functionCodeElem.isJsonNull()) { - throw new IllegalStateException(String.format("Value for '%s' is invalid", JSON_FUNCTION_CODE)); - } - try { - functionCodeNumeric = functionCodeElem.getAsInt(); - } catch (ClassCastException | IllegalStateException e) { - throw new IllegalStateException(String.format("Value for '%s' is invalid", JSON_FUNCTION_CODE), e); - } - ModbusWriteFunctionCode functionCode = ModbusWriteFunctionCode.fromFunctionCode(functionCodeNumeric); - int address; - if (addressElem == null || addressElem.isJsonNull()) { - throw new IllegalStateException(String.format("Value for '%s' is invalid", JSON_ADDRESS)); - } - try { - address = addressElem.getAsInt(); - } catch (ClassCastException | IllegalStateException e) { - throw new IllegalStateException(String.format("Value for '%s' is invalid", JSON_ADDRESS), e); - } - int maxTries; - if (maxTriesElem == null || maxTriesElem.isJsonNull()) { - // Go with default - maxTries = DEFAULT_MAX_TRIES; - } else { - try { - maxTries = maxTriesElem.getAsInt(); - } catch (ClassCastException | IllegalStateException e) { - throw new IllegalStateException(String.format("Value for '%s' is invalid", JSON_MAX_TRIES), e); - } - } - - if (valuesElem == null || valuesElem.isJsonNull()) { - throw new IllegalArgumentException(String.format("Expecting non-null value, got: %s", valuesElem)); - } - - AtomicBoolean writeSingle = new AtomicBoolean(false); - switch (functionCode) { - case WRITE_COIL: - writeSingle.set(true); - if (valuesElem.size() != 1) { - throw new IllegalArgumentException(String - .format("Expecting single value with functionCode=%s, got: %d", functionCode, valuesElem)); - } - // fall-through to WRITE_MULTIPLE_COILS - case WRITE_MULTIPLE_COILS: - if (valuesElem.size() == 0) { - throw new IllegalArgumentException("Must provide at least one coil"); - } else if (valuesElem.size() > ModbusConstants.MAX_BITS_WRITE_COUNT) { - throw new IllegalArgumentException( - String.format("Trying to write too many coils (%d). Maximum is %s", valuesElem.size(), - ModbusConstants.MAX_BITS_WRITE_COUNT)); - } - BitArray bits = new BitArray(valuesElem.size()); - for (int i = 0; i < valuesElem.size(); i++) { - bits.setBit(i, valuesElem.get(i).getAsInt() != 0); - } - return new ModbusWriteCoilRequestBlueprint(unitId, address, bits, !writeSingle.get(), maxTries); - case WRITE_SINGLE_REGISTER: - writeSingle.set(true); - if (valuesElem.size() != 1) { - throw new IllegalArgumentException(String - .format("Expecting single value with functionCode=%s, got: %d", functionCode, valuesElem)); - } - // fall-through to WRITE_MULTIPLE_REGISTERS - case WRITE_MULTIPLE_REGISTERS: { - int[] registers = new int[valuesElem.size()]; - if (registers.length == 0) { - throw new IllegalArgumentException("Must provide at least one register"); - } else if (valuesElem.size() > ModbusConstants.MAX_REGISTERS_WRITE_COUNT) { - throw new IllegalArgumentException( - String.format("Trying to write too many registers (%d). Maximum is %s", valuesElem.size(), - ModbusConstants.MAX_REGISTERS_WRITE_COUNT)); - } - for (int i = 0; i < valuesElem.size(); i++) { - registers[i] = valuesElem.get(i).getAsInt(); - } - return new ModbusWriteRegisterRequestBlueprint(unitId, address, new ModbusRegisterArray(registers), - !writeSingle.get(), maxTries); - } - default: - throw new IllegalArgumentException("Unknown function code"); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/AbstractRequestComparer.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/AbstractRequestComparer.java deleted file mode 100644 index 72f7a976d4068..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/AbstractRequestComparer.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeMatcher; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; - -/** - * @author Sami Salonen - Initial contribution - */ -abstract class AbstractRequestComparer extends TypeSafeMatcher { - - private int expectedUnitId; - private int expectedAddress; - private ModbusWriteFunctionCode expectedFunctionCode; - private int expectedMaxTries; - - public AbstractRequestComparer(int expectedUnitId, int expectedAddress, - ModbusWriteFunctionCode expectedFunctionCode, int expectedMaxTries) { - this.expectedUnitId = expectedUnitId; - this.expectedAddress = expectedAddress; - this.expectedFunctionCode = expectedFunctionCode; - this.expectedMaxTries = expectedMaxTries; - } - - @Override - public void describeTo(Description description) { - description.appendText("should return request with"); - description.appendText(" unitID="); - description.appendValue(expectedUnitId); - description.appendText(" address="); - description.appendValue(expectedAddress); - description.appendText(" functionCode="); - description.appendValue(expectedFunctionCode); - description.appendText(" maxTries="); - description.appendValue(expectedMaxTries); - } - - @SuppressWarnings("null") - @Override - protected boolean matchesSafely(T item) { - if (item.getUnitID() != expectedUnitId) { - return false; - } - if (item.getReference() != expectedAddress) { - return false; - } - if (item.getFunctionCode() != expectedFunctionCode) { - return false; - } - if (item.getMaxTries() != expectedMaxTries) { - return false; - } - return doMatchData(item); - } - - protected abstract boolean doMatchData(T item); -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BasicBitArrayTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BasicBitArrayTest.java deleted file mode 100644 index 2d65dce319f67..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BasicBitArrayTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.BitArray; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BasicBitArrayTest { - - @Test - public void testGetBitAndSetBit() { - BitArray data1 = new BitArray(true, false, true); - assertThat(data1.size(), is(equalTo(3))); - assertThat(data1.getBit(0), is(equalTo(true))); - assertThat(data1.getBit(1), is(equalTo(false))); - assertThat(data1.getBit(2), is(equalTo(true))); - - data1.setBit(1, true); - data1.setBit(2, false); - assertThat(data1.size(), is(equalTo(3))); - assertThat(data1.getBit(0), is(equalTo(true))); - assertThat(data1.getBit(1), is(equalTo(true))); - assertThat(data1.getBit(2), is(equalTo(false))); - } - - @Test - public void testGetBitAndSetBit2() { - BitArray data1 = new BitArray(3); - assertThat(data1.size(), is(equalTo(3))); - assertThat(data1.getBit(0), is(equalTo(false))); - assertThat(data1.getBit(1), is(equalTo(false))); - assertThat(data1.getBit(2), is(equalTo(false))); - - data1.setBit(1, true); - assertThat(data1.size(), is(equalTo(3))); - assertThat(data1.getBit(0), is(equalTo(false))); - assertThat(data1.getBit(1), is(equalTo(true))); - assertThat(data1.getBit(2), is(equalTo(false))); - - data1.setBit(1, false); - assertThat(data1.size(), is(equalTo(3))); - assertThat(data1.getBit(0), is(equalTo(false))); - assertThat(data1.getBit(1), is(equalTo(false))); - assertThat(data1.getBit(2), is(equalTo(false))); - } - - @Test - public void testOutOfBounds() { - BitArray data1 = new BitArray(true, false, true); - assertThrows(IndexOutOfBoundsException.class, () -> data1.getBit(3)); - } - - @Test - public void testOutOfBounds2() { - BitArray data1 = new BitArray(true, false, true); - assertThrows(IndexOutOfBoundsException.class, () -> data1.getBit(-1)); - } - - @Test - public void testOutOfBounds3() { - BitArray data1 = new BitArray(3); - assertThrows(IndexOutOfBoundsException.class, () -> data1.getBit(3)); - } - - @Test - public void testOutOfBounds4() { - BitArray data1 = new BitArray(3); - assertThrows(IndexOutOfBoundsException.class, () -> data1.getBit(-1)); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesCommandToRegistersTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesCommandToRegistersTest.java deleted file mode 100644 index f4e562df61b53..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesCommandToRegistersTest.java +++ /dev/null @@ -1,331 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Collection; -import java.util.Collections; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.commons.lang.NotImplementedException; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.types.Command; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesCommandToRegistersTest { - - private static short[] shorts(int... ints) { - short[] shorts = new short[ints.length]; - for (int i = 0; i < ints.length; i++) { - short s = (short) ints[i]; - shorts[i] = s; - } - return shorts; - } - - public static Collection data() { - return Collections.unmodifiableList(Stream - .of(new Object[] { new DecimalType("1.0"), ValueType.BIT, IllegalArgumentException.class }, - new Object[] { new DecimalType("1.0"), ValueType.INT8, IllegalArgumentException.class }, - // - // INT16 - // - new Object[] { new DecimalType("1.0"), ValueType.INT16, shorts(1) }, - new Object[] { new DecimalType("1.6"), ValueType.INT16, shorts(1) }, - new Object[] { new DecimalType("2.6"), ValueType.INT16, shorts(2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.INT16, shorts(-1004), }, - // within bounds for signed int16 - new Object[] { new DecimalType("32000"), ValueType.INT16, shorts(32000), }, - new Object[] { new DecimalType("-32000"), ValueType.INT16, shorts(-32000), }, - // out bounds for signed int16, but not for uint16 - new Object[] { new DecimalType("60000"), ValueType.INT16, shorts(60000), }, - new Object[] { new DecimalType("64000"), ValueType.INT16, shorts(64000), }, // - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004.4"), - // 70004 -> 0x00011174 (int) -> 0x1174 (short) = 4468 - ValueType.INT16, shorts(4468), }, - // - // UINT16 (same as INT16) - // - new Object[] { new DecimalType("1.0"), ValueType.UINT16, shorts(1) }, - new Object[] { new DecimalType("1.6"), ValueType.UINT16, shorts(1) }, - new Object[] { new DecimalType("2.6"), ValueType.UINT16, shorts(2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.UINT16, shorts(-1004), }, - // within bounds for signed int16 - new Object[] { new DecimalType("32000"), ValueType.UINT16, shorts(32000), }, - new Object[] { new DecimalType("-32000"), ValueType.UINT16, shorts(-32000), }, - // out bounds for signed int16, but not for uint16 - new Object[] { new DecimalType("60000"), ValueType.UINT16, shorts(60000), }, - new Object[] { new DecimalType("64000"), ValueType.UINT16, shorts(64000), }, // - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004.4"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.UINT16, shorts(0x1174), }, - // - // INT32 - // - new Object[] { new DecimalType("1.0"), ValueType.INT32, shorts(0, 1) }, - new Object[] { new DecimalType("1.6"), ValueType.INT32, shorts(0, 1) }, - new Object[] { new DecimalType("2.6"), ValueType.INT32, shorts(0, 2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.INT32, - // -1004 = 0xFFFFFC14 (32bit) = - shorts(0xFFFF, 0xFC14), }, - new Object[] { new DecimalType("64000"), ValueType.INT32, shorts(0, 64000), }, // - // within signed int32 range: +-2,000,000,00 - new Object[] { new DecimalType("-2000000000"), ValueType.INT32, shorts(0x88CA, 0x6C00), }, - new Object[] { new DecimalType("2000000000"), ValueType.INT32, shorts(0x7735, 0x9400), }, - // out bounds for signed int32, but not for uint32 - new Object[] { new DecimalType("3000000000"), ValueType.INT32, shorts(0xB2D0, 0x5E00), }, // - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), - // 5000000000 -> 0x12a05f200 () -> 0x1174 (16bit) - ValueType.INT32, shorts(0x2a05, 0xf200), }, - // - // UINT32 (same as INT32) - // - new Object[] { new DecimalType("1.0"), ValueType.UINT32, shorts(0, 1) }, - new Object[] { new DecimalType("1.6"), ValueType.UINT32, shorts(0, 1) }, - new Object[] { new DecimalType("2.6"), ValueType.UINT32, shorts(0, 2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.UINT32, - // -1004 = 0xFFFFFC14 (32bit) = - shorts(0xFFFF, 0xFC14), }, - new Object[] { new DecimalType("64000"), ValueType.UINT32, shorts(0, 64000), }, // - // within signed int32 range: +-2,000,000,00 - new Object[] { new DecimalType("-2000000000"), ValueType.UINT32, shorts(0x88CA, 0x6C00), }, - new Object[] { new DecimalType("2000000000"), ValueType.UINT32, shorts(0x7735, 0x9400), }, - // out bounds for signed int32, but not for uint32 - new Object[] { new DecimalType("3000000000"), ValueType.UINT32, shorts(0xB2D0, 0x5E00), }, // - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), - // 5000000000 -> 0x12a05f200 () -> 0x1174 (16bit) - ValueType.UINT32, shorts(0x2a05, 0xf200), }, - // - // INT32_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.INT32_SWAP, shorts(1, 0) }, - new Object[] { new DecimalType("1.6"), ValueType.INT32_SWAP, shorts(1, 0) }, - new Object[] { new DecimalType("2.6"), ValueType.INT32_SWAP, shorts(2, 0) }, - new Object[] { new DecimalType("-1004.4"), ValueType.INT32_SWAP, - // -1004 = 0xFFFFFC14 (32bit) - shorts(0xFC14, 0xFFFF), }, - new Object[] { new DecimalType("64000"), ValueType.INT32_SWAP, shorts(64000, 0), }, - // within signed int32 range: +-2,000,000,00 - new Object[] { new DecimalType("-2000000000"), ValueType.INT32_SWAP, shorts(0x6C00, 0x88CA), }, - new Object[] { new DecimalType("2000000000"), ValueType.INT32_SWAP, shorts(0x9400, 0x7735), }, - // out bounds for signed int32, but not for uint32 - new Object[] { new DecimalType("3000000000"), ValueType.INT32_SWAP, shorts(0x5E00, 0xB2D0), }, // - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), - // 5000000000 -> 0x12a05f200 - ValueType.INT32_SWAP, shorts(0xf200, 0x2a05), }, - // - // UINT32_SWAP (same as INT32_SWAP) - // - new Object[] { new DecimalType("1.0"), ValueType.UINT32_SWAP, shorts(1, 0) }, - new Object[] { new DecimalType("1.6"), ValueType.UINT32_SWAP, shorts(1, 0) }, - new Object[] { new DecimalType("2.6"), ValueType.UINT32_SWAP, shorts(2, 0) }, - new Object[] { new DecimalType("-1004.4"), ValueType.UINT32_SWAP, - // -1004 = 0xFFFFFC14 (32bit) - shorts(0xFC14, 0xFFFF), }, - new Object[] { new DecimalType("64000"), ValueType.UINT32_SWAP, shorts(64000, 0), }, - // within signed int32 range: +-2,000,000,00 - new Object[] { new DecimalType("-2000000000"), ValueType.UINT32_SWAP, shorts(0x6C00, 0x88CA), }, - new Object[] { new DecimalType("2000000000"), ValueType.UINT32_SWAP, shorts(0x9400, 0x7735), }, - // out bounds for signed int32, but not for uint32 - new Object[] { new DecimalType("3000000000"), ValueType.UINT32_SWAP, shorts(0x5E00, 0xB2D0), }, // - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), - // 5000000000 -> 0x12a05f200 - ValueType.UINT32_SWAP, shorts(0xf200, 0x2a05), }, - // - // FLOAT32 - // - new Object[] { new DecimalType("1.0"), ValueType.FLOAT32, shorts(0x3F80, 0x0000) }, - new Object[] { new DecimalType("1.6"), ValueType.FLOAT32, shorts(0x3FCC, 0xCCCD) }, - new Object[] { new DecimalType("2.6"), ValueType.FLOAT32, shorts(0x4026, 0x6666) }, - new Object[] { new DecimalType("-1004.4"), ValueType.FLOAT32, shorts(0xC47B, 0x199A), }, - new Object[] { new DecimalType("64000"), ValueType.FLOAT32, shorts(0x477A, 0x0000), }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004.4"), ValueType.FLOAT32, shorts(0x4788, 0xBA33), }, - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), ValueType.FLOAT32, shorts(0x4F95, 0x02F9), }, - // - // FLOAT32_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) }, - new Object[] { new DecimalType("1.6"), ValueType.FLOAT32_SWAP, shorts(0xCCCD, 0x3FCC) }, - new Object[] { new DecimalType("2.6"), ValueType.FLOAT32_SWAP, shorts(0x6666, 0x4026) }, - new Object[] { new DecimalType("-1004.4"), ValueType.FLOAT32_SWAP, shorts(0x199A, 0xC47B), }, - new Object[] { new DecimalType("64000"), ValueType.FLOAT32_SWAP, shorts(0x0000, 0x477A), }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004.4"), ValueType.FLOAT32_SWAP, shorts(0xBA33, 0x4788), }, - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), ValueType.FLOAT32_SWAP, shorts(0x02F9, 0x4F95) }, - // ON/OFF - new Object[] { OnOffType.ON, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) }, - new Object[] { OnOffType.OFF, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x0000) }, - // OPEN - new Object[] { OpenClosedType.OPEN, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) }, - new Object[] { OpenClosedType.OPEN, ValueType.INT16, shorts(1) }, - // CLOSED - new Object[] { OpenClosedType.CLOSED, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x0000) }, - new Object[] { OpenClosedType.CLOSED, ValueType.INT16, shorts(0x0000) }, - // Unsupported command - new Object[] { IncreaseDecreaseType.INCREASE, ValueType.FLOAT32_SWAP, - NotImplementedException.class }, - - // - // INT64 - // - new Object[] { new DecimalType("1.0"), ValueType.INT64, shorts(0, 0, 0, 1) }, - new Object[] { new DecimalType("1.6"), ValueType.INT64, shorts(0, 0, 0, 1) }, - new Object[] { new DecimalType("2.6"), ValueType.INT64, shorts(0, 0, 0, 2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.INT64, - shorts(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), }, - new Object[] { new DecimalType("64000"), ValueType.INT64, shorts(0, 0, 0, 64000), }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.INT64, shorts(0x0, 0x8, 0x0, 0x0), }, - // within signed int64 range: +-9,200,000,000,000,000,000 - new Object[] { new DecimalType("-9200000000000000000"), ValueType.INT64, - shorts(0x8053, 0x08BE, 0x6268, 0x0000), }, - new Object[] { new DecimalType("9200000000000000000"), ValueType.INT64, - shorts(0x7FAC, 0xF741, 0x9D98, 0x0000), }, - // within unsigned int64 range (but out of range for signed int64) - new Object[] { new DecimalType("18200000000000000000"), ValueType.INT64, - shorts(0xFC93, 0x6392, 0x801C, 0x0000), }, - new Object[] { - // out of bounds of unsigned 64bit - new DecimalType("3498348904359085439088905"), - // should pick the low 64 bits - ValueType.INT64, shorts(0xDFC5, 0xBBB7, 0x772E, 0x7909), }, - - // - // UINT64 (same as INT64) - // - new Object[] { new DecimalType("1.0"), ValueType.UINT64, shorts(0, 0, 0, 1) }, - new Object[] { new DecimalType("1.6"), ValueType.UINT64, shorts(0, 0, 0, 1) }, - new Object[] { new DecimalType("2.6"), ValueType.UINT64, shorts(0, 0, 0, 2) }, - new Object[] { new DecimalType("-1004.4"), ValueType.UINT64, - shorts(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), }, - new Object[] { new DecimalType("64000"), ValueType.UINT64, shorts(0, 0, 0, 64000), }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.UINT64, shorts(0x0, 0x8, 0x0, 0x0), }, - // within signed int64 range: +-9,200,000,000,000,000,000 - new Object[] { new DecimalType("-9200000000000000000"), ValueType.UINT64, - shorts(0x8053, 0x08BE, 0x6268, 0x0000), }, - new Object[] { new DecimalType("9200000000000000000"), ValueType.UINT64, - shorts(0x7FAC, 0xF741, 0x9D98, 0x0000), }, - // within unsigned int64 range (but out of range for signed int64) - new Object[] { new DecimalType("18200000000000000000"), ValueType.UINT64, - shorts(0xFC93, 0x6392, 0x801C, 0x0000), }, - new Object[] { - // out of bounds of unsigned 64bit - new DecimalType("3498348904359085439088905"), - // should pick the low 64 bits - ValueType.UINT64, shorts(0xDFC5, 0xBBB7, 0x772E, 0x7909), }, - - // - // INT64_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.INT64_SWAP, shorts(1, 0, 0, 0) }, - new Object[] { new DecimalType("1.6"), ValueType.INT64_SWAP, shorts(1, 0, 0, 0) }, - new Object[] { new DecimalType("2.6"), ValueType.INT64_SWAP, shorts(2, 0, 0, 0) }, - new Object[] { new DecimalType("-1004.4"), ValueType.INT64_SWAP, - shorts(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), }, - new Object[] { new DecimalType("64000"), ValueType.INT64_SWAP, shorts(64000, 0, 0, 0), }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.INT64_SWAP, shorts(0x0, 0x0, 0x8, 0x0), }, - new Object[] { - // out of bounds of unsigned 64bit - new DecimalType("3498348904359085439088905"), - // should pick the low 64 bits - ValueType.INT64_SWAP, shorts(0x7909, 0x772E, 0xBBB7, 0xDFC5), }, - - // - // UINT64_SWAP (same as INT64_SWAP) - // - new Object[] { new DecimalType("1.0"), ValueType.UINT64_SWAP, shorts(1, 0, 0, 0) }, - new Object[] { new DecimalType("1.6"), ValueType.UINT64_SWAP, shorts(1, 0, 0, 0) }, - new Object[] { new DecimalType("2.6"), ValueType.UINT64_SWAP, shorts(2, 0, 0, 0) }, - new Object[] { new DecimalType("-1004.4"), ValueType.UINT64_SWAP, - shorts(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), }, - new Object[] { new DecimalType("64000"), ValueType.UINT64_SWAP, shorts(64000, 0, 0, 0), }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.UINT64_SWAP, shorts(0x0, 0x0, 0x8, 0x0), }, - new Object[] { - // out of bounds of unsigned 64bit - new DecimalType("3498348904359085439088905"), - // should pick the low 64 bits - ValueType.UINT64_SWAP, shorts(0x7909, 0x772E, 0xBBB7, 0xDFC5), }) - .collect(Collectors.toList())); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @ParameterizedTest - @MethodSource("data") - public void testCommandToRegisters(Command command, ValueType type, Object expectedResult) { - if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) { - assertThrows((Class) expectedResult, () -> ModbusBitUtilities.commandToRegisters(command, type)); - return; - } - - ModbusRegisterArray registers = ModbusBitUtilities.commandToRegisters(command, type); - short[] expectedRegisters = (short[]) expectedResult; - - assertThat(String.format("register index command=%s, type=%s", command, type), registers.size(), - is(equalTo(expectedRegisters.length))); - for (int i = 0; i < expectedRegisters.length; i++) { - int expectedRegisterDataUnsigned = expectedRegisters[i] & 0xffff; - int actualUnsigned = registers.getRegister(i); - - assertThat(String.format("register index i=%d, command=%s, type=%s", i, command, type), actualUnsigned, - is(equalTo(expectedRegisterDataUnsigned))); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractBitTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractBitTest.java deleted file mode 100644 index 8f743682417e4..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractBitTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.ModbusBitUtilities; - -/** - * - * Tests for extractBit - * - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractBitTest { - - @Test - public void testExtractBitWithRegisterIndexAndBitIndex() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - - { - int registerIndex = 0; - int[] expectedBitsFromLSBtoMSB = new int[] { // - 1, 0, 1, 0, 0, 1, 0, 0, // lo byte, with increasing significance - 1, 0, 0, 0, 0, 1, 0, 0 // hi byte, with increasing significance - }; - for (int bitIndex = 0; bitIndex < expectedBitsFromLSBtoMSB.length; bitIndex++) { - assertEquals(expectedBitsFromLSBtoMSB[bitIndex], - ModbusBitUtilities.extractBit(bytes, registerIndex, bitIndex), - String.format("bitIndex=%d", bitIndex)); - } - } - { - int registerIndex = 1; - int[] expectedBitsFromLSBtoMSB = new int[] { // - 1, 0, 0, 1, 0, 1, 0, 0, // lo byte, with increasing significance - 1, 0, 0, 0, 1, 1, 0, 0 // hi byte, with increasing significance - }; - for (int bitIndex = 0; bitIndex < expectedBitsFromLSBtoMSB.length; bitIndex++) { - assertEquals(expectedBitsFromLSBtoMSB[bitIndex], - ModbusBitUtilities.extractBit(bytes, registerIndex, bitIndex), - String.format("bitIndex=%d", bitIndex)); - } - } - } - - @Test - public void testExtractBitWithRegisterIndexAndBitIndexOOB() { - - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, 3, 0)); - } - - @Test - public void testExtractBitWithRegisterIndexAndBitIndexOOB2() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, 0, 17)); - } - - @Test - public void testExtractBitWithRegisterIndexAndBitIndexOOB3() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, 0, -1)); - } - - @Test - public void testExtractBitWithRegisterIndexAndBitIndexOOB4() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, -1, 0)); - } - - @Test - public void testExtractBitWithSingleIndex() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - int[] expectedBits = new int[] { // - 1, 0, 1, 0, 0, 1, 0, 0, // 1st register: lo byte, with increasing significance - 1, 0, 0, 0, 0, 1, 0, 0, // 1st register: hi byte, with increasing significance - 1, 0, 0, 1, 0, 1, 0, 0, // 2nd register: lo byte, with increasing significance - 1, 0, 0, 0, 1, 1, 0, 0 // 2nd register: hi byte, with increasing significance - }; - for (int bitIndex = 0; bitIndex < expectedBits.length; bitIndex++) { - assertEquals(expectedBits[bitIndex], ModbusBitUtilities.extractBit(bytes, bitIndex), - String.format("bitIndex=%d", bitIndex)); - assertEquals(expectedBits[bitIndex], ModbusBitUtilities.extractBit(bytes, bitIndex), - String.format("bitIndex=%d", bitIndex)); - } - } - - @Test - public void testExtractBitWithSingleIndexOOB() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, 32)); - } - - @Test - public void testExtractBitWithSingleIndexOOB2() { - byte[] bytes = new byte[] { 0b00100001, // hi byte of 1st register - 0b00100101, // lo byte of 1st register - 0b00110001, // hi byte of 2nd register - 0b00101001 }; // lo byte of 2nd register - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractBit(bytes, -1)); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractFloat32Test.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractFloat32Test.java deleted file mode 100644 index 388a9464f1648..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractFloat32Test.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.nio.ByteBuffer; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.ModbusBitUtilities; - -/** - * - * Tests for 'special' float values such as infinity and NaN. These are not covered in detail in - * {@link BitUtilitiesExtractIndividualMethodsTest} and - * {@link BitUtilitiesExtractStateFromRegistersTest} - * - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractFloat32Test { - - /** - * Creates a byte array with byteOffset number of zeroes, followed by 32bit of data represented by data - * - * @param data actual data payload - * @param byteOffset number of zeros padded - * @return byte array of size 4 + byteOffset - */ - private static byte[] bytes(int data, int byteOffset) { - ByteBuffer buffer = ByteBuffer.allocate(4 + byteOffset); - for (int i = 0; i < byteOffset; i++) { - buffer.put((byte) 0); - } - buffer.putInt(data); - return buffer.array(); - } - - private static void testFloat(float number) { - int data = Float.floatToIntBits(number); - for (int byteOffset = 0; byteOffset < 5; byteOffset++) { - byte[] bytes = bytes(data, byteOffset); - float actual = ModbusBitUtilities.extractFloat32(bytes, byteOffset); - float expected = Float.intBitsToFloat(data); - // Strict comparison of the float values with the exception of NaN - assertTrue(Float.isNaN(expected) ? Float.isNaN(actual) : expected == actual, - String.format("Testing %f (%s) with offset %d, got %f (%s)", expected, Integer.toBinaryString(data), - byteOffset, actual, Integer.toBinaryString(Float.floatToRawIntBits(actual)))); - } - } - - @Test - public void testExtractFloat32Inf() { - testFloat(Float.POSITIVE_INFINITY); - } - - @Test - public void testExtractFloat32NegInf() { - testFloat(Float.NEGATIVE_INFINITY); - } - - @Test - public void testExtractFloat32NaN() { - testFloat(Float.NaN); - } - - @Test - public void testExtractFloat32Regular() { - testFloat(1.3f); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractIndividualMethodsTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractIndividualMethodsTest.java deleted file mode 100644 index 83f1a629a2b1c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractIndividualMethodsTest.java +++ /dev/null @@ -1,266 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.Stream.Builder; - -import org.eclipse.jdt.annotation.Nullable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.core.library.types.DecimalType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractIndividualMethodsTest { - - public static Collection data() { - // We use test data from BitUtilitiesExtractStateFromRegistersTest - // In BitUtilitiesExtractStateFromRegistersTest the data is aligned to registers - // - // Here (in registerVariations) we generate offsetted variations of the byte data - // to test extractXX which can operate on data aligned on byte-level, not just data aligned on-register level - Collection data = BitUtilitiesExtractStateFromRegistersTest.data(); - return data.stream().flatMap(values -> { - Object expectedResult = values[0]; - ValueType type = (ValueType) values[1]; - ModbusRegisterArray registers = (ModbusRegisterArray) values[2]; - int index = (int) values[3]; - return registerVariations(expectedResult, type, registers, index); - }).collect(Collectors.toList()); - } - - public static Stream filteredTestData(ValueType type) { - return data().stream().filter(values -> (ValueType) values[1] == type); - } - - /** - * Generate register variations for extractXX functions - * - * - * @return entries of (byte[], byteIndex) - */ - private static Stream registerVariations(Object expectedResult, ValueType type, - ModbusRegisterArray registers, int index) { - byte[] origBytes = registers.getBytes(); - int origRegisterIndex = index; - int origByteIndex = origRegisterIndex * 2; - - Builder streamBuilder = Stream.builder(); - for (int offset = 0; offset < 5; offset++) { - int byteIndex = origByteIndex + offset; - byte[] bytesOffsetted = new byte[origBytes.length + offset]; - for (int i = 0; i < bytesOffsetted.length; i++) { - bytesOffsetted[i] = 99; - } - System.arraycopy(origBytes, 0, bytesOffsetted, offset, origBytes.length); - // offsetted: - streamBuilder.add(new Object[] { expectedResult, type, bytesOffsetted, byteIndex }); - - // offsetted, with no extra bytes following - // (this is only done for successfull cases to avoid copyOfRange padding with zeros - if (!(expectedResult instanceof Class)) { - byte[] bytesOffsettedCutExtra = Arrays.copyOfRange(bytesOffsetted, 0, byteIndex + type.getBits() / 8); - if (bytesOffsettedCutExtra.length != bytesOffsetted.length) { - streamBuilder.add(new Object[] { expectedResult, type, bytesOffsettedCutExtra, byteIndex }); - } - } - } - return streamBuilder.build(); - } - - private void testIndividual(Object expectedResult, ValueType type, byte[] bytes, int byteIndex, - Supplier methodUnderTest, Function expectedPrimitive) { - testIndividual(expectedResult, type, bytes, byteIndex, methodUnderTest, expectedPrimitive, null); - } - - @SuppressWarnings("unchecked") - private void testIndividual(Object expectedResult, ValueType type, byte[] bytes, int byteIndex, - Supplier methodUnderTest, Function expectedPrimitive, - @Nullable Number defaultWhenEmptyOptional) { - String testExplanation = String.format("bytes=%s, byteIndex=%d, type=%s", Arrays.toString(bytes), byteIndex, - type); - final Object expectedNumber; - if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) { - assertThrows((Class) expectedResult, () -> methodUnderTest.get()); - } else if (expectedResult instanceof Optional) { - assertTrue(!((Optional) expectedResult).isPresent()); - if (defaultWhenEmptyOptional == null) { - fail("Should provide defaultWhenEmptyOptional"); - } - return; - } else { - DecimalType expectedDecimal = (DecimalType) expectedResult; - expectedNumber = expectedPrimitive.apply(expectedDecimal); - assertEquals(expectedNumber, methodUnderTest.get(), testExplanation); - } - } - - public static Stream filteredTestDataSInt16() { - return filteredTestData(ValueType.INT16); - } - - @ParameterizedTest - @MethodSource("filteredTestDataSInt16") - public void testExtractIndividualSInt16(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractSInt16(bytes, byteIndex), - decimal -> decimal.shortValue()); - } - - public static Stream filteredTestDataUInt16() { - return filteredTestData(ValueType.UINT16); - } - - @ParameterizedTest - @MethodSource("filteredTestDataUInt16") - public void testExtractIndividualUInt16(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractUInt16(bytes, byteIndex), - decimal -> decimal.intValue()); - } - - public static Stream filteredTestDataSInt32() { - return filteredTestData(ValueType.INT32); - } - - @ParameterizedTest - @MethodSource("filteredTestDataSInt32") - public void testExtractIndividualSInt32(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractSInt32(bytes, byteIndex), - decimal -> decimal.intValue()); - } - - public static Stream filteredTestDataUInt32() { - return filteredTestData(ValueType.UINT32); - } - - @ParameterizedTest - @MethodSource("filteredTestDataUInt32") - public void testExtractIndividualUInt32(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractUInt32(bytes, byteIndex), - decimal -> decimal.longValue()); - } - - public static Stream filteredTestDataSInt32Swap() { - return filteredTestData(ValueType.INT32_SWAP); - } - - @ParameterizedTest - @MethodSource("filteredTestDataSInt32Swap") - public void testExtractIndividualSInt32Swap(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractSInt32Swap(bytes, byteIndex), decimal -> decimal.intValue()); - } - - public static Stream filteredTestDataUInt32Swap() { - return filteredTestData(ValueType.UINT32_SWAP); - } - - @ParameterizedTest - @MethodSource("filteredTestDataUInt32Swap") - public void testExtractIndividualUInt32Swap(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractUInt32Swap(bytes, byteIndex), decimal -> decimal.longValue()); - } - - public static Stream filteredTestDataSInt64() { - return filteredTestData(ValueType.INT64); - } - - @ParameterizedTest - @MethodSource("filteredTestDataSInt64") - public void testExtractIndividualSInt64(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractSInt64(bytes, byteIndex), - decimal -> decimal.longValue()); - } - - public static Stream filteredTestDataUInt64() { - return filteredTestData(ValueType.UINT64); - } - - @ParameterizedTest - @MethodSource("filteredTestDataUInt64") - public void testExtractIndividualUInt64(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, () -> ModbusBitUtilities.extractUInt64(bytes, byteIndex), - decimal -> decimal.toBigDecimal().toBigIntegerExact()); - } - - public static Stream filteredTestDataSInt64Swap() { - return filteredTestData(ValueType.INT64_SWAP); - } - - @ParameterizedTest - @MethodSource("filteredTestDataSInt64Swap") - public void testExtractIndividualSInt64Swap(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractSInt64Swap(bytes, byteIndex), decimal -> decimal.longValue()); - } - - public static Stream filteredTestDataUInt64Swap() { - return filteredTestData(ValueType.UINT64_SWAP); - } - - @ParameterizedTest - @MethodSource("filteredTestDataUInt64Swap") - public void testExtractIndividualUInt64Swap(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractUInt64Swap(bytes, byteIndex), - decimal -> decimal.toBigDecimal().toBigIntegerExact()); - } - - public static Stream filteredTestDataFloat32() { - return filteredTestData(ValueType.FLOAT32); - } - - @ParameterizedTest - @MethodSource("filteredTestDataFloat32") - public void testExtractIndividualFloat32(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractFloat32(bytes, byteIndex), decimal -> decimal.floatValue(), Float.NaN); - } - - public static Stream filteredTestDataFloat32Swap() { - return filteredTestData(ValueType.FLOAT32_SWAP); - } - - @ParameterizedTest - @MethodSource("filteredTestDataFloat32Swap") - public void testExtractIndividualFloat32Swap(Object expectedResult, ValueType type, byte[] bytes, int byteIndex) - throws InstantiationException, IllegalAccessException { - testIndividual(expectedResult, type, bytes, byteIndex, - () -> ModbusBitUtilities.extractFloat32Swap(bytes, byteIndex), decimal -> decimal.floatValue(), - Float.NaN); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractInt8Test.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractInt8Test.java deleted file mode 100644 index 811b12d31df2c..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractInt8Test.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.ModbusBitUtilities; - -/** - * - * Tests for extractSInt8 and extractUInt8 - * - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractInt8Test { - - @Test - public void extractSInt8WithSingleIndex() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertEquals(-1, ModbusBitUtilities.extractSInt8(bytes, 0)); - assertEquals(2, ModbusBitUtilities.extractSInt8(bytes, 1)); - assertEquals(3, ModbusBitUtilities.extractSInt8(bytes, 2)); - } - - @Test - public void extractSInt8WithSingleIndexOOB() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractSInt8(bytes, 3)); - } - - @Test - public void extractSInt8WithSingleIndexOOB2() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractSInt8(bytes, -1)); - } - - @Test - public void extractSInt8WithRegisterIndexAndHiByte() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertEquals(-1, ModbusBitUtilities.extractSInt8(bytes, 0, true)); - assertEquals(2, ModbusBitUtilities.extractSInt8(bytes, 0, false)); - assertEquals(3, ModbusBitUtilities.extractSInt8(bytes, 1, true)); - assertEquals(4, ModbusBitUtilities.extractSInt8(bytes, 1, false)); - } - - @Test - public void extractSInt8WithRegisterIndexAndHiByteOOB() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractSInt8(bytes, 2, true)); - } - - @Test - public void extractSInt8WithRegisterIndexAndHiByteOOB2() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractSInt8(bytes, -1, true)); - } - - // - // unsigned int8 follows - // - - @Test - public void extractUInt8WithSingleIndex() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertEquals(255, ModbusBitUtilities.extractUInt8(bytes, 0)); - assertEquals(2, ModbusBitUtilities.extractUInt8(bytes, 1)); - assertEquals(3, ModbusBitUtilities.extractUInt8(bytes, 2)); - } - - @Test - public void extractUInt8WithSingleIndexOOB() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractUInt8(bytes, 3)); - } - - @Test - public void extractUInt8WithSingleIndexOOB2() { - byte[] bytes = new byte[] { -1, 2, 3 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractUInt8(bytes, -1)); - } - - @Test - public void extractUInt8WithRegisterIndexAndHiByte() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertEquals(255, ModbusBitUtilities.extractUInt8(bytes, 0, true)); - assertEquals(2, ModbusBitUtilities.extractUInt8(bytes, 0, false)); - assertEquals(3, ModbusBitUtilities.extractUInt8(bytes, 1, true)); - assertEquals(4, ModbusBitUtilities.extractUInt8(bytes, 1, false)); - } - - @Test - public void extractUInt8WithRegisterIndexAndHiByteOOB() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractUInt8(bytes, 2, true)); - } - - @Test - public void extractUInt8WithRegisterIndexAndHiByteOOB2() { - byte[] bytes = new byte[] { -1, 2, 3, 4 }; - assertThrows(IllegalArgumentException.class, () -> ModbusBitUtilities.extractUInt8(bytes, 255, true)); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStateFromRegistersTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStateFromRegistersTest.java deleted file mode 100644 index 195c68c8ac752..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStateFromRegistersTest.java +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNull; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.core.library.types.DecimalType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusRegisterArray; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractStateFromRegistersTest { - - private static ModbusRegisterArray shortArrayToRegisterArray(int... arr) { - return new ModbusRegisterArray(arr); - } - - public static Collection data() { - return Collections.unmodifiableList(Stream.of( - // - // BIT - // - new Object[] { new DecimalType("1.0"), ValueType.BIT, - shortArrayToRegisterArray(1 << 5 | 1 << 4 | 1 << 15), 4 }, - new Object[] { new DecimalType("1.0"), ValueType.BIT, - shortArrayToRegisterArray(1 << 5 | 1 << 4 | 1 << 15), 15 }, - new Object[] { new DecimalType("0.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5), 7 }, - new Object[] { new DecimalType("1.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5), 5 }, - new Object[] { new DecimalType("0.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5), 4 }, - new Object[] { new DecimalType("0.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5), 0 }, - new Object[] { new DecimalType("0.0"), ValueType.BIT, shortArrayToRegisterArray(0, 0), 15 }, - new Object[] { new DecimalType("1.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5, 1 << 4), 5 }, - new Object[] { new DecimalType("1.0"), ValueType.BIT, shortArrayToRegisterArray(1 << 5, 1 << 4), 20 }, - new Object[] { IllegalArgumentException.class, ValueType.BIT, shortArrayToRegisterArray(1 << 5), 16 }, - new Object[] { IllegalArgumentException.class, ValueType.BIT, shortArrayToRegisterArray(1 << 5), 200 }, - new Object[] { IllegalArgumentException.class, ValueType.BIT, shortArrayToRegisterArray(), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.BIT, shortArrayToRegisterArray(0, 0), 32 }, - // - // INT8 - // - new Object[] { new DecimalType("5.0"), ValueType.INT8, shortArrayToRegisterArray(5), 0 }, - new Object[] { new DecimalType("-5.0"), ValueType.INT8, shortArrayToRegisterArray(-5), 0 }, - new Object[] { new DecimalType("3.0"), ValueType.INT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3), 0 }, - new Object[] { new DecimalType("6.0"), ValueType.INT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3), 1 }, - new Object[] { new DecimalType("4.0"), ValueType.INT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3, 4), 2 }, - new Object[] { new DecimalType("6.0"), ValueType.INT8, - shortArrayToRegisterArray(55, ((byte) 6 << 8) | (byte) 3), 3 }, - new Object[] { IllegalArgumentException.class, ValueType.INT8, shortArrayToRegisterArray(1), 2 }, - new Object[] { IllegalArgumentException.class, ValueType.INT8, shortArrayToRegisterArray(1, 2), 4 }, - // - // UINT8 - // - new Object[] { new DecimalType("5.0"), ValueType.UINT8, shortArrayToRegisterArray(5), 0 }, - new Object[] { new DecimalType("251.0"), ValueType.UINT8, shortArrayToRegisterArray(-5), 0 }, - new Object[] { new DecimalType("3.0"), ValueType.UINT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3), 0 }, - new Object[] { new DecimalType("6.0"), ValueType.UINT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3), 1 }, - new Object[] { new DecimalType("4.0"), ValueType.UINT8, - shortArrayToRegisterArray(((byte) 6 << 8) | (byte) 3, 4), 2 }, - new Object[] { new DecimalType("6.0"), ValueType.UINT8, - shortArrayToRegisterArray(55, ((byte) 6 << 8) | (byte) 3), 3 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT8, shortArrayToRegisterArray(1), 2 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT8, shortArrayToRegisterArray(1, 2), 4 }, - - // - // INT16 - // - new Object[] { new DecimalType("1.0"), ValueType.INT16, shortArrayToRegisterArray(1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.INT16, shortArrayToRegisterArray(2), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT16, shortArrayToRegisterArray(-1004), 0 }, - new Object[] { new DecimalType("-1536"), ValueType.INT16, shortArrayToRegisterArray(64000), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT16, shortArrayToRegisterArray(4, -1004), 1 }, - new Object[] { new DecimalType("-1004"), ValueType.INT16, shortArrayToRegisterArray(-1004, 4), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.INT16, shortArrayToRegisterArray(4, -1004), - 2 }, - // - // UINT16 - // - new Object[] { new DecimalType("1.0"), ValueType.UINT16, shortArrayToRegisterArray(1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.UINT16, shortArrayToRegisterArray(2), 0 }, - new Object[] { new DecimalType("64532"), ValueType.UINT16, shortArrayToRegisterArray(-1004), 0 }, - new Object[] { new DecimalType("64000"), ValueType.UINT16, shortArrayToRegisterArray(64000), 0 }, - new Object[] { new DecimalType("64532"), ValueType.UINT16, shortArrayToRegisterArray(4, -1004), 1 }, - new Object[] { new DecimalType("64532"), ValueType.UINT16, shortArrayToRegisterArray(-1004, 4), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT16, shortArrayToRegisterArray(4, -1004), - 2 }, - // - // INT32 - // - new Object[] { new DecimalType("1.0"), ValueType.INT32, shortArrayToRegisterArray(0, 1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.INT32, shortArrayToRegisterArray(0, 2), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFFFF, 0xFC14), 0 }, - new Object[] { new DecimalType("64000"), ValueType.INT32, shortArrayToRegisterArray(0, 64000), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0x4, 0xFFFF, 0xFC14), 1 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFFFF, 0xFC14, 0x4), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32, shortArrayToRegisterArray(4, -1004), - 1 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32, shortArrayToRegisterArray(4, -1004), - 2 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32, shortArrayToRegisterArray(0, 0, 0), 2 }, - // - // UINT32 - // - new Object[] { new DecimalType("1.0"), ValueType.UINT32, shortArrayToRegisterArray(0, 1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.UINT32, shortArrayToRegisterArray(0, 2), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFFFF, 0xFC14), 0 }, - new Object[] { new DecimalType("64000"), ValueType.UINT32, shortArrayToRegisterArray(0, 64000), 0 }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.UINT32, shortArrayToRegisterArray(1, 4468), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFFFF, 0xFC14, 0x5), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0x5, 0xFFFF, 0xFC14), 1 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32, shortArrayToRegisterArray(4, -1004), - 1 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32, shortArrayToRegisterArray(4, -1004), - 2 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32, shortArrayToRegisterArray(0, 0, 0), - 2 }, - // - // INT32_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.INT32_SWAP, shortArrayToRegisterArray(1, 0), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.INT32_SWAP, shortArrayToRegisterArray(2, 0), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32_SWAP, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFC14, 0xFFFF), 0 }, - new Object[] { new DecimalType("64000"), ValueType.INT32_SWAP, shortArrayToRegisterArray(64000, 0), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32_SWAP, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0x4, 0xFC14, 0xFFFF), 1 }, - new Object[] { new DecimalType("-1004"), ValueType.INT32_SWAP, - // -1004 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFC14, 0xFFFF, 0x4), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32_SWAP, - shortArrayToRegisterArray(4, -1004), 1 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32_SWAP, - shortArrayToRegisterArray(4, -1004), 2 }, - new Object[] { IllegalArgumentException.class, ValueType.INT32_SWAP, shortArrayToRegisterArray(0, 0, 0), - 2 }, - // - // UINT32_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.UINT32_SWAP, shortArrayToRegisterArray(1, 0), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.UINT32_SWAP, shortArrayToRegisterArray(2, 0), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32_SWAP, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFC14, 0xFFFF), 0 }, - new Object[] { new DecimalType("64000"), ValueType.UINT32_SWAP, shortArrayToRegisterArray(64000, 0), - 0 }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType("70004"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.UINT32_SWAP, shortArrayToRegisterArray(4468, 1), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32_SWAP, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0xFC14, 0xFFFF, 0x5), 0 }, - new Object[] { new DecimalType("4294966292"), ValueType.UINT32_SWAP, - // 4294966292 = 0xFFFFFC14 (32bit) = - shortArrayToRegisterArray(0x5, 0xFC14, 0xFFFF), 1 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32_SWAP, - shortArrayToRegisterArray(4, -1004), 1 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32_SWAP, - shortArrayToRegisterArray(4, -1004), 2 }, - new Object[] { IllegalArgumentException.class, ValueType.UINT32_SWAP, - shortArrayToRegisterArray(0, 0, 0), 2 }, - // - // FLOAT32 - // - new Object[] { new DecimalType("1.0"), ValueType.FLOAT32, shortArrayToRegisterArray(0x3F80, 0x0000), - 0 }, - new Object[] { new DecimalType(1.6f), ValueType.FLOAT32, shortArrayToRegisterArray(0x3FCC, 0xCCCD), 0 }, - new Object[] { new DecimalType(2.6f), ValueType.FLOAT32, shortArrayToRegisterArray(0x4026, 0x6666), 0 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32, shortArrayToRegisterArray(0xC47B, 0x199A), - 0 }, - new Object[] { new DecimalType("64000"), ValueType.FLOAT32, shortArrayToRegisterArray(0x477A, 0x0000), - 0 }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType(70004.4f), ValueType.FLOAT32, shortArrayToRegisterArray(0x4788, 0xBA33), 0 }, - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), ValueType.FLOAT32, shortArrayToRegisterArray(0x4F95, 0x02F9), - 0 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32, - shortArrayToRegisterArray(0x4, 0xC47B, 0x199A), 1 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32, - shortArrayToRegisterArray(0xC47B, 0x199A, 0x4), 0 }, - new Object[] { // equivalent of NaN - Optional.empty(), ValueType.FLOAT32, shortArrayToRegisterArray(0x7fc0, 0x0000), 0 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32, - shortArrayToRegisterArray(0x4, 0x0, 0x0, 0x0, 0xC47B, 0x199A), 4 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32, shortArrayToRegisterArray(4, -1004), - 1 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32, shortArrayToRegisterArray(4, -1004), - 2 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32, shortArrayToRegisterArray(0, 0, 0), - 2 }, - // - // FLOAT32_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x0000, 0x3F80), 0 }, - new Object[] { new DecimalType(1.6f), ValueType.FLOAT32_SWAP, shortArrayToRegisterArray(0xCCCD, 0x3FCC), - 0 }, - new Object[] { new DecimalType(2.6f), ValueType.FLOAT32_SWAP, shortArrayToRegisterArray(0x6666, 0x4026), - 0 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x199A, 0xC47B), 0 }, - new Object[] { new DecimalType("64000"), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x0000, 0x477A), 0 }, - new Object[] { // equivalent of NaN - Optional.empty(), ValueType.FLOAT32_SWAP, shortArrayToRegisterArray(0x0000, 0x7fc0), 0 }, - new Object[] { - // out of bounds of unsigned 16bit (0 to 65,535) - new DecimalType(70004.4f), ValueType.FLOAT32_SWAP, shortArrayToRegisterArray(0xBA33, 0x4788), - 0 }, - new Object[] { - // out of bounds of unsigned 32bit (0 to 4,294,967,295) - new DecimalType("5000000000"), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x02F9, 0x4F95), 0 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x4, 0x199A, 0xC47B), 1 }, - new Object[] { new DecimalType(-1004.4f), ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0x199A, 0xC47B, 0x4), 0 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(4, -1004), 1 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(4, -1004), 2 }, - new Object[] { IllegalArgumentException.class, ValueType.FLOAT32_SWAP, - shortArrayToRegisterArray(0, 0, 0), 2 }, - - // - // INT64 - // - new Object[] { new DecimalType("1.0"), ValueType.INT64, shortArrayToRegisterArray(0, 0, 0, 1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.INT64, shortArrayToRegisterArray(0, 0, 0, 2), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT64, - shortArrayToRegisterArray(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), 0 }, - new Object[] { new DecimalType("64000"), ValueType.INT64, shortArrayToRegisterArray(0, 0, 0, 64000), - 0 }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), ValueType.INT64, shortArrayToRegisterArray(0x0, 0x8, 0x0, 0x0), - 0 }, - new Object[] { new DecimalType("-2322243636186679031"), ValueType.INT64, - shortArrayToRegisterArray(0xDFC5, 0xBBB7, 0x772E, 0x7909), 0 }, - // would read over the registers - new Object[] { IllegalArgumentException.class, ValueType.INT64, - shortArrayToRegisterArray(0xDFC5, 0xBBB7, 0x772E, 0x7909), 1 }, - // would read over the registers - new Object[] { IllegalArgumentException.class, ValueType.INT64, - shortArrayToRegisterArray(0xDFC5, 0xBBB7, 0x772E, 0x7909), 2 }, - // 4 registers expected, only 3 available - new Object[] { IllegalArgumentException.class, ValueType.INT64, - shortArrayToRegisterArray(0xDFC5, 0xBBB7, 0x772E), 0 }, - - // - // UINT64 - // - new Object[] { new DecimalType("1.0"), ValueType.UINT64, shortArrayToRegisterArray(0, 0, 0, 1), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.UINT64, shortArrayToRegisterArray(0, 0, 0, 2), 0 }, - new Object[] { new DecimalType("18446744073709550612"), ValueType.UINT64, - shortArrayToRegisterArray(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), 0 }, - new Object[] { new DecimalType("64000"), ValueType.UINT64, shortArrayToRegisterArray(0, 0, 0, 64000), - 0 }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), ValueType.UINT64, shortArrayToRegisterArray(0x0, 0x8, 0x0, 0x0), - 0 }, - new Object[] { new DecimalType("16124500437522872585"), ValueType.UINT64, - shortArrayToRegisterArray(0xDFC5, 0xBBB7, 0x772E, 0x7909), 0 }, - - // - // INT64_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.INT64_SWAP, shortArrayToRegisterArray(1, 0, 0, 0), 0 }, - new Object[] { new DecimalType("2.0"), ValueType.INT64_SWAP, shortArrayToRegisterArray(2, 0, 0, 0), 0 }, - new Object[] { new DecimalType("-1004"), ValueType.INT64_SWAP, - shortArrayToRegisterArray(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), 0 }, - new Object[] { new DecimalType("64000"), ValueType.INT64_SWAP, - shortArrayToRegisterArray(64000, 0, 0, 0), 0 }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), - // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit) - ValueType.INT64_SWAP, shortArrayToRegisterArray(0x0, 0x0, 0x8, 0x0), 0 }, - new Object[] { new DecimalType("-2322243636186679031"), ValueType.INT64_SWAP, - - shortArrayToRegisterArray(0x7909, 0x772E, 0xBBB7, 0xDFC5), 0 }, - - // - // UINT64_SWAP - // - new Object[] { new DecimalType("1.0"), ValueType.UINT64_SWAP, shortArrayToRegisterArray(1, 0, 0, 0), - 0 }, - new Object[] { new DecimalType("2.0"), ValueType.UINT64_SWAP, shortArrayToRegisterArray(2, 0, 0, 0), - 0 }, - new Object[] { new DecimalType("18446744073709550612"), ValueType.UINT64_SWAP, - shortArrayToRegisterArray(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), 0 }, - new Object[] { new DecimalType("64000"), ValueType.UINT64_SWAP, - shortArrayToRegisterArray(64000, 0, 0, 0), 0 }, - new Object[] { - // out of bounds of unsigned 32bit - new DecimalType("34359738368"), ValueType.UINT64_SWAP, - shortArrayToRegisterArray(0x0, 0x0, 0x8, 0x0), 0 }, - new Object[] { - // out of bounds of unsigned 64bit - new DecimalType("16124500437522872585"), ValueType.UINT64_SWAP, - shortArrayToRegisterArray(0x7909, 0x772E, 0xBBB7, 0xDFC5), 0 }) - .collect(Collectors.toList())); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @ParameterizedTest - @MethodSource("data") - public void testextractStateFromRegisters(Object expectedResult, ValueType type, ModbusRegisterArray registers, - int index) { - if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) { - assertThrows((Class) expectedResult, - () -> ModbusBitUtilities.extractStateFromRegisters(registers, index, type)); - return; - } - - Optional<@NonNull DecimalType> actualState = ModbusBitUtilities.extractStateFromRegisters(registers, index, - type); - // Wrap given expectedResult to Optional, if necessary - Optional<@NonNull DecimalType> expectedStateWrapped = expectedResult instanceof DecimalType - ? Optional.of((DecimalType) expectedResult) - : (Optional<@NonNull DecimalType>) expectedResult; - assertThat(String.format("registers=%s, index=%d, type=%s", registers, index, type), actualState, - is(equalTo(expectedStateWrapped))); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStringTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStringTest.java deleted file mode 100644 index bd762862f815d..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesExtractStringTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Collections; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.Stream.Builder; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.io.transport.modbus.ModbusBitUtilities; -import org.openhab.io.transport.modbus.ModbusRegisterArray; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesExtractStringTest { - - private static ModbusRegisterArray shortArrayToRegisterArray(int... arr) { - return new ModbusRegisterArray(arr); - } - - public static Collection data() { - return Collections.unmodifiableList(Stream.of( - new Object[] { "", shortArrayToRegisterArray(0), 0, 0, StandardCharsets.UTF_8 }, - new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00), 0, 5, - StandardCharsets.UTF_8 }, - new Object[] { "he", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00), 0, 2, StandardCharsets.UTF_8 }, // limited - // by - // count=2 - new Object[] { "hello ", shortArrayToRegisterArray(0, 0, 0x6865, 0x6c6c, 0x6f20, 0, 0), 2, 6, - StandardCharsets.UTF_8 }, - new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00, 0x0000, 0x0000), 0, 10, - StandardCharsets.UTF_8 }, - new Object[] { "árvíztűrő tükörfúrógép", - shortArrayToRegisterArray(0xc3a1, 0x7276, 0xc3ad, 0x7a74, 0xc5b1, 0x72c5, 0x9120, 0x74c3, - 0xbc6b, 0xc3b6, 0x7266, 0xc3ba, 0x72c3, 0xb367, 0xc3a9, 0x7000), - 0, 32, StandardCharsets.UTF_8 }, - new Object[] { "你好,世界", - shortArrayToRegisterArray(0xe4bd, 0xa0e5, 0xa5bd, 0xefbc, 0x8ce4, 0xb896, 0xe795, 0x8c00), 0, - 16, StandardCharsets.UTF_8 }, - new Object[] { "árvíztűrő tükörfúrógép", - shortArrayToRegisterArray(0xe172, 0x76ed, 0x7a74, 0xfb72, 0xf520, 0x74fc, 0x6bf6, 0x7266, - 0xfa72, 0xf367, 0xe970), - 0, 22, Charset.forName("ISO-8859-2") }, - // Example where registers contain 0 byte in between -- only the data preceding zero byte is parsed - new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00, 0x776f, 0x726c, 0x64), 0, 10, - StandardCharsets.UTF_8 }, - - // Invalid values - // 0xe4 = "ä" in extended ascii but not covered by US_ASCII. Will be replaced by � - new Object[] { "�", shortArrayToRegisterArray(0xe400), 0, 2, StandardCharsets.US_ASCII }, - // out of bounds - new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 2, 4, - StandardCharsets.UTF_8 }, - // negative index - new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 0, -1, - StandardCharsets.UTF_8 }, - // out of bounds - new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 0, 5, - StandardCharsets.UTF_8 }) - .collect(Collectors.toList())); - } - - public static Stream dataWithByteVariations() { - return data().stream().flatMap(vals -> { - Object expected = vals[0]; - ModbusRegisterArray registers = (ModbusRegisterArray) vals[1]; - int index = (int) vals[2]; - int length = (int) vals[3]; - Charset charset = (Charset) vals[4]; - - byte[] origBytes = registers.getBytes(); - int origRegisterIndex = index; - int origByteIndex = origRegisterIndex * 2; - - Builder streamBuilder = Stream.builder(); - for (int offset = 0; offset < 5; offset++) { - byte[] bytesOffsetted = new byte[origBytes.length + offset]; - System.arraycopy(origBytes, 0, bytesOffsetted, offset, origBytes.length); - streamBuilder.add( - new Object[] { expected, offset, bytesOffsetted, origByteIndex + offset, length, charset }); - } - Stream variations = streamBuilder.build(); - return variations; - }); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @ParameterizedTest - @MethodSource("data") - public void testExtractStringFromRegisters(Object expectedResult, ModbusRegisterArray registers, int index, - int length, Charset charset) { - if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) { - assertThrows((Class) expectedResult, - () -> ModbusBitUtilities.extractStringFromRegisters(registers, index, length, charset)); - return; - } else { - String actualState = ModbusBitUtilities.extractStringFromRegisters(registers, index, length, charset); - assertEquals(actualState, expectedResult, - String.format("registers=%s, index=%d, length=%d", registers, index, length)); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @ParameterizedTest - @MethodSource("dataWithByteVariations") - public void testExtractStringFromBytes(Object expectedResult, int byteOffset, byte[] bytes, int byteIndex, - int length, Charset charset) { - if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) { - assertThrows((Class) expectedResult, - () -> ModbusBitUtilities.extractStringFromBytes(bytes, byteIndex, length, charset)); - return; - } else { - String actualState = ModbusBitUtilities.extractStringFromBytes(bytes, byteIndex, length, charset); - assertEquals(actualState, expectedResult, String.format("registers=%s, index=%d, length=%d, byteIndex=%d", - bytes, byteIndex, length, byteIndex)); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesTranslateCommand2BooleanTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesTranslateCommand2BooleanTest.java deleted file mode 100644 index 1c211f00c12ad..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/BitUtilitiesTranslateCommand2BooleanTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.util.Optional; - -import org.junit.jupiter.api.Test; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.io.transport.modbus.ModbusBitUtilities; - -/** - * @author Sami Salonen - Initial contribution - */ -public class BitUtilitiesTranslateCommand2BooleanTest { - - @Test - public void testZero() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(DecimalType.ZERO); - assertThat(actual, is(equalTo(Optional.of(false)))); - } - - @Test - public void testNegative() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(new DecimalType(-3.4)); - assertThat(actual, is(equalTo(Optional.of(true)))); - } - - @Test - public void testPositive() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(new DecimalType(3.4)); - assertThat(actual, is(equalTo(Optional.of(true)))); - } - - @Test - public void testOn() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(OnOffType.ON); - assertThat(actual, is(equalTo(Optional.of(true)))); - } - - @Test - public void testOpen() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(OpenClosedType.OPEN); - assertThat(actual, is(equalTo(Optional.of(true)))); - } - - @Test - public void testOff() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(OnOffType.OFF); - assertThat(actual, is(equalTo(Optional.of(false)))); - } - - @Test - public void testClosed() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(OpenClosedType.CLOSED); - assertThat(actual, is(equalTo(Optional.of(false)))); - } - - @Test - public void testUnknown() { - Optional actual = ModbusBitUtilities.translateCommand2Boolean(IncreaseDecreaseType.INCREASE); - assertThat(actual, is(equalTo(Optional.empty()))); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/CoilMatcher.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/CoilMatcher.java deleted file mode 100644 index 7a5bb9e330aa6..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/CoilMatcher.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import java.util.Arrays; -import java.util.Objects; -import java.util.stream.StreamSupport; - -import org.hamcrest.Description; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; - -/** - * @author Sami Salonen - Initial contribution - */ -class CoilMatcher extends AbstractRequestComparer { - - private Boolean[] expectedCoils; - - public CoilMatcher(int expectedUnitId, int expectedAddress, int expectedMaxTries, - ModbusWriteFunctionCode expectedFunctionCode, Boolean... expectedCoils) { - super(expectedUnitId, expectedAddress, expectedFunctionCode, expectedMaxTries); - this.expectedCoils = expectedCoils; - } - - @Override - public void describeTo(Description description) { - super.describeTo(description); - description.appendText(" coils="); - description.appendValue(Arrays.toString(expectedCoils)); - } - - @Override - protected boolean doMatchData(ModbusWriteCoilRequestBlueprint item) { - Object[] actual = StreamSupport.stream(item.getCoils().spliterator(), false).toArray(); - return Objects.deepEquals(actual, expectedCoils); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/IntegrationTestSupport.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/IntegrationTestSupport.java deleted file mode 100644 index ae573be3041ef..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/IntegrationTestSupport.java +++ /dev/null @@ -1,357 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -import java.io.File; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.function.LongSupplier; - -import org.apache.commons.lang.NotImplementedException; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Spy; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -import org.openhab.core.test.java.JavaTest; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.internal.ModbusManagerImpl; - -import gnu.io.SerialPort; -import net.wimpi.modbus.Modbus; -import net.wimpi.modbus.ModbusCoupler; -import net.wimpi.modbus.ModbusIOException; -import net.wimpi.modbus.io.ModbusTransport; -import net.wimpi.modbus.msg.ModbusRequest; -import net.wimpi.modbus.net.ModbusSerialListener; -import net.wimpi.modbus.net.ModbusTCPListener; -import net.wimpi.modbus.net.ModbusUDPListener; -import net.wimpi.modbus.net.SerialConnection; -import net.wimpi.modbus.net.SerialConnectionFactory; -import net.wimpi.modbus.net.TCPSlaveConnection; -import net.wimpi.modbus.net.TCPSlaveConnection.ModbusTCPTransportFactory; -import net.wimpi.modbus.net.TCPSlaveConnectionFactory; -import net.wimpi.modbus.net.UDPSlaveTerminal; -import net.wimpi.modbus.net.UDPSlaveTerminal.ModbusUDPTransportFactoryImpl; -import net.wimpi.modbus.net.UDPSlaveTerminalFactory; -import net.wimpi.modbus.net.UDPTerminal; -import net.wimpi.modbus.procimg.SimpleProcessImage; -import net.wimpi.modbus.util.AtomicCounter; -import net.wimpi.modbus.util.SerialParameters; - -/** - * @author Sami Salonen - Initial contribution - */ -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.WARN) -public class IntegrationTestSupport extends JavaTest { - - public enum ServerType { - TCP, - UDP, - SERIAL - } - - /** - * Servers to test - * Serial is system dependent - */ - public static final ServerType[] TEST_SERVERS = new ServerType[] { ServerType.TCP - // ServerType.UDP, - // ServerType.SERIAL - }; - - // One can perhaps test SERIAL with https://github.com/freemed/tty0tty - // and using those virtual ports? Not the same thing as real serial device of course - private static String SERIAL_SERVER_PORT = "/dev/pts/7"; - private static String SERIAL_CLIENT_PORT = "/dev/pts/8"; - - private static SerialParameters SERIAL_PARAMETERS_CLIENT = new SerialParameters(SERIAL_CLIENT_PORT, 115200, - SerialPort.FLOWCONTROL_NONE, SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, - SerialPort.PARITY_NONE, Modbus.SERIAL_ENCODING_ASCII, false, 1000); - - private static SerialParameters SERIAL_PARAMETERS_SERVER = new SerialParameters(SERIAL_SERVER_PORT, - SERIAL_PARAMETERS_CLIENT.getBaudRate(), SERIAL_PARAMETERS_CLIENT.getFlowControlIn(), - SERIAL_PARAMETERS_CLIENT.getFlowControlOut(), SERIAL_PARAMETERS_CLIENT.getDatabits(), - SERIAL_PARAMETERS_CLIENT.getStopbits(), SERIAL_PARAMETERS_CLIENT.getParity(), - SERIAL_PARAMETERS_CLIENT.getEncoding(), SERIAL_PARAMETERS_CLIENT.isEcho(), 1000); - - static { - System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "trace"); - System.setProperty("gnu.io.rxtx.SerialPorts", SERIAL_SERVER_PORT + File.pathSeparator + SERIAL_CLIENT_PORT); - } - - /** - * Max time to wait for connections/requests from client - */ - protected int MAX_WAIT_REQUESTS_MILLIS = 1000; - - /** - * The server runs in single thread, only one connection is accepted at a time. - * This makes the tests as strict as possible -- connection must be closed. - */ - private static final int SERVER_THREADS = 1; - protected static int SLAVE_UNIT_ID = 1; - - private static AtomicCounter udpServerIndex = new AtomicCounter(0); - - protected @Spy TCPSlaveConnectionFactory tcpConnectionFactory = new TCPSlaveConnectionFactoryImpl(); - protected @Spy UDPSlaveTerminalFactory udpTerminalFactory = new UDPSlaveTerminalFactoryImpl(); - protected @Spy SerialConnectionFactory serialConnectionFactory = new SerialConnectionFactoryImpl(); - - protected ResultCaptor modbustRequestCaptor; - - protected ModbusTCPListener tcpListener; - protected ModbusUDPListener udpListener; - protected ModbusSerialListener serialListener; - protected SimpleProcessImage spi; - protected int tcpModbusPort = -1; - protected int udpModbusPort = -1; - protected ServerType serverType = ServerType.TCP; - protected long artificialServerWait = 0; - - protected NonOSGIModbusManager modbusManager; - - private Thread serialServerThread = new Thread("ModbusTransportTestsSerialServer") { - @Override - public void run() { - serialListener = new ModbusSerialListener(SERIAL_PARAMETERS_SERVER); - } - }; - - protected static InetAddress localAddress() throws UnknownHostException { - return InetAddress.getByName("127.0.0.1"); - } - - @BeforeEach - public void setUp() throws Exception { - modbustRequestCaptor = new ResultCaptor<>(new LongSupplier() { - - @Override - public long getAsLong() { - return artificialServerWait; - } - }); - modbusManager = new NonOSGIModbusManager(); - startServer(); - } - - @AfterEach - public void tearDown() { - stopServer(); - modbusManager.close(); - } - - protected void waitForRequests(int expectedRequestCount) { - waitForAssert( - () -> assertThat(modbustRequestCaptor.getAllReturnValues().size(), is(equalTo(expectedRequestCount))), - MAX_WAIT_REQUESTS_MILLIS, 10); - } - - protected void waitForConnectionsReceived(int expectedConnections) { - waitForAssert(() -> { - if (ServerType.TCP.equals(serverType)) { - verify(tcpConnectionFactory, times(expectedConnections)).create(any(Socket.class)); - } else if (ServerType.UDP.equals(serverType)) { - // No-op - // verify(udpTerminalFactory, times(expectedConnections)).create(any(InetAddress.class), - // any(Integer.class)); - } else if (ServerType.SERIAL.equals(serverType)) { - // No-op - } else { - throw new NotImplementedException(); - } - }, MAX_WAIT_REQUESTS_MILLIS, 10); - } - - private void startServer() throws UnknownHostException, InterruptedException { - spi = new SimpleProcessImage(); - ModbusCoupler.getReference().setProcessImage(spi); - ModbusCoupler.getReference().setMaster(false); - ModbusCoupler.getReference().setUnitID(SLAVE_UNIT_ID); - - if (ServerType.TCP.equals(serverType)) { - startTCPServer(); - } else if (ServerType.UDP.equals(serverType)) { - startUDPServer(); - } else if (ServerType.SERIAL.equals(serverType)) { - startSerialServer(); - } else { - throw new NotImplementedException(); - } - } - - private void stopServer() { - if (ServerType.TCP.equals(serverType)) { - tcpListener.stop(); - } else if (ServerType.UDP.equals(serverType)) { - udpListener.stop(); - System.err.println(udpModbusPort); - } else if (ServerType.SERIAL.equals(serverType)) { - try { - serialServerThread.join(100); - } catch (InterruptedException e) { - System.err.println("Serial server thread .join() interrupted! Will interrupt it now."); - } - serialServerThread.interrupt(); - } else { - throw new NotImplementedException(); - } - } - - private void startUDPServer() throws UnknownHostException, InterruptedException { - udpListener = new ModbusUDPListener(localAddress(), udpTerminalFactory); - for (int portCandidate = 10000 + udpServerIndex.increment(); portCandidate < 20000; portCandidate++) { - try { - DatagramSocket socket = new DatagramSocket(portCandidate); - socket.close(); - udpListener.setPort(portCandidate); - break; - } catch (SocketException e) { - continue; - } - } - - udpListener.start(); - waitForUDPServerStartup(); - assertNotSame(-1, udpModbusPort); - assertNotSame(0, udpModbusPort); - } - - private void waitForUDPServerStartup() throws InterruptedException { - // Query server port. It seems to take time (probably due to thread starting) - waitFor(() -> udpListener.getLocalPort() > 0, 5, 10_000); - udpModbusPort = udpListener.getLocalPort(); - } - - private void startTCPServer() throws UnknownHostException, InterruptedException { - // Serve single user at a time - tcpListener = new ModbusTCPListener(SERVER_THREADS, localAddress(), tcpConnectionFactory); - // Use any open port - tcpListener.setPort(0); - tcpListener.start(); - // Query server port. It seems to take time (probably due to thread starting) - waitForTCPServerStartup(); - assertNotSame(-1, tcpModbusPort); - assertNotSame(0, tcpModbusPort); - } - - private void waitForTCPServerStartup() throws InterruptedException { - waitFor(() -> tcpListener.getLocalPort() > 0, 10_000, 5); - tcpModbusPort = tcpListener.getLocalPort(); - } - - private void startSerialServer() throws UnknownHostException, InterruptedException { - serialServerThread.start(); - Thread.sleep(1000); - } - - public ModbusSlaveEndpoint getEndpoint() { - assert tcpModbusPort > 0; - return new ModbusTCPSlaveEndpoint("127.0.0.1", tcpModbusPort); - } - - /** - * Transport factory that spies the created transport items - */ - public class SpyingModbusTCPTransportFactory extends ModbusTCPTransportFactory { - - @Override - public ModbusTransport create(Socket socket) { - ModbusTransport transport = spy(super.create(socket)); - // Capture requests produced by our server transport - try { - doAnswer(modbustRequestCaptor).when(transport).readRequest(); - } catch (ModbusIOException e) { - throw new RuntimeException(e); - } - return transport; - } - } - - public class SpyingModbusUDPTransportFactory extends ModbusUDPTransportFactoryImpl { - - @Override - public ModbusTransport create(UDPTerminal terminal) { - ModbusTransport transport = spy(super.create(terminal)); - // Capture requests produced by our server transport - try { - doAnswer(modbustRequestCaptor).when(transport).readRequest(); - } catch (ModbusIOException e) { - throw new RuntimeException(e); - } - return transport; - } - } - - public class TCPSlaveConnectionFactoryImpl implements TCPSlaveConnectionFactory { - - @Override - public TCPSlaveConnection create(Socket socket) { - return new TCPSlaveConnection(socket, new SpyingModbusTCPTransportFactory()); - } - } - - public class UDPSlaveTerminalFactoryImpl implements UDPSlaveTerminalFactory { - - @Override - public UDPSlaveTerminal create(InetAddress interfac, int port) { - UDPSlaveTerminal terminal = new UDPSlaveTerminal(interfac, new SpyingModbusUDPTransportFactory(), 1); - terminal.setLocalPort(port); - return terminal; - } - } - - public class SerialConnectionFactoryImpl implements SerialConnectionFactory { - @Override - public SerialConnection create(SerialParameters parameters) { - SerialConnection serialConnection = new SerialConnection(parameters) { - @Override - public ModbusTransport getModbusTransport() { - ModbusTransport transport = spy(super.getModbusTransport()); - try { - doAnswer(modbustRequestCaptor).when(transport).readRequest(); - } catch (ModbusIOException e) { - throw new RuntimeException(e); - } - return transport; - } - }; - return serialConnection; - } - } - - public static class NonOSGIModbusManager extends ModbusManagerImpl implements AutoCloseable { - public NonOSGIModbusManager() { - activate(new HashMap<>()); - } - - @Override - public void close() { - deactivate(); - } - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ModbusSlaveEndpointTestCase.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ModbusSlaveEndpointTestCase.java deleted file mode 100644 index 35a7eb02f63c0..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ModbusSlaveEndpointTestCase.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.endpoint.ModbusSerialSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusUDPSlaveEndpoint; - -import gnu.io.SerialPort; -import net.wimpi.modbus.Modbus; - -/** - * @author Sami Salonen - Initial contribution - */ -public class ModbusSlaveEndpointTestCase { - - @Test - public void testEqualsSameTcp() { - ModbusTCPSlaveEndpoint e1 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - ModbusTCPSlaveEndpoint e2 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - assertEquals(e1, e2); - } - - @Test - public void testEqualsSameSerial2() { - ModbusSerialSlaveEndpoint e1 = new ModbusSerialSlaveEndpoint("port1", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - ModbusSerialSlaveEndpoint e2 = new ModbusSerialSlaveEndpoint("port1", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - assertEquals(e1, e2); - } - - /** - * even though different echo parameter & baud rate, the endpoints are considered the same due to same port - */ - @Test - public void testEqualsSameSerial3() { - ModbusSerialSlaveEndpoint e1 = new ModbusSerialSlaveEndpoint("port1", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - ModbusSerialSlaveEndpoint e2 = new ModbusSerialSlaveEndpoint("port1", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, false, 500); - assertEquals(e1, e2); - assertEquals(e1.hashCode(), e2.hashCode()); - } - - @Test - public void testEqualsDifferentSerial() { - ModbusSerialSlaveEndpoint e1 = new ModbusSerialSlaveEndpoint("port1", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - ModbusSerialSlaveEndpoint e2 = new ModbusSerialSlaveEndpoint("port2", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - assertNotEquals(e1, e2); - assertNotEquals(e1.hashCode(), e2.hashCode()); - } - - @Test - public void testEqualsDifferentTCPPort() { - ModbusTCPSlaveEndpoint e1 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - ModbusTCPSlaveEndpoint e2 = new ModbusTCPSlaveEndpoint("127.0.0.1", 501); - assertNotEquals(e1, e2); - assertNotEquals(e1.hashCode(), e2.hashCode()); - } - - @Test - public void testEqualsDifferentTCPHost() { - ModbusTCPSlaveEndpoint e1 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - ModbusTCPSlaveEndpoint e2 = new ModbusTCPSlaveEndpoint("127.0.0.2", 501); - assertNotEquals(e1, e2); - assertNotEquals(e1.hashCode(), e2.hashCode()); - } - - @Test - public void testEqualsDifferentProtocol() { - ModbusTCPSlaveEndpoint e1 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - ModbusUDPSlaveEndpoint e2 = new ModbusUDPSlaveEndpoint("127.0.0.1", 500); - assertNotEquals(e1, e2); - assertNotEquals(e1.hashCode(), e2.hashCode()); - } - - @Test - public void testEqualsDifferentProtocol2() { - ModbusTCPSlaveEndpoint e1 = new ModbusTCPSlaveEndpoint("127.0.0.1", 500); - ModbusSerialSlaveEndpoint e2 = new ModbusSerialSlaveEndpoint("port2", 9600, SerialPort.FLOWCONTROL_NONE, - SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, - Modbus.DEFAULT_SERIAL_ENCODING, true, 500); - assertNotEquals(e1, e2); - assertNotEquals(e1.hashCode(), e2.hashCode()); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/RegisterMatcher.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/RegisterMatcher.java deleted file mode 100644 index 2eb0c4a87387f..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/RegisterMatcher.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import java.util.Arrays; -import java.util.Objects; -import java.util.stream.IntStream; -import java.util.stream.StreamSupport; - -import org.hamcrest.Description; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; - -/** - * @author Sami Salonen - Initial contribution - */ -class RegisterMatcher extends AbstractRequestComparer { - - private Integer[] expectedRegisterValues; - - public RegisterMatcher(int expectedUnitId, int expectedAddress, int expectedMaxTries, - ModbusWriteFunctionCode expectedFunctionCode, Integer... expectedRegisterValues) { - super(expectedUnitId, expectedAddress, expectedFunctionCode, expectedMaxTries); - this.expectedRegisterValues = expectedRegisterValues; - } - - @Override - public void describeTo(Description description) { - super.describeTo(description); - description.appendText(" registers="); - description.appendValue(Arrays.toString(expectedRegisterValues)); - } - - @Override - protected boolean doMatchData(ModbusWriteRegisterRequestBlueprint item) { - ModbusRegisterArray registers = item.getRegisters(); - Object[] actual = StreamSupport - .stream(IntStream.range(0, registers.size()).mapToObj(registers::getRegister).spliterator(), false) - .toArray(); - return Objects.deepEquals(actual, expectedRegisterValues); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ResultCaptor.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ResultCaptor.java deleted file mode 100644 index 75c9a696505a2..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ResultCaptor.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import java.util.ArrayList; -import java.util.function.LongSupplier; - -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * @author Sami Salonen - Initial contribution - * - * @param - */ -public class ResultCaptor implements Answer { - - private ArrayList results = new ArrayList<>(); - private LongSupplier longSupplier; - - public ResultCaptor(LongSupplier longSupplier) { - this.longSupplier = longSupplier; - } - - public ArrayList getAllReturnValues() { - return results; - } - - @SuppressWarnings("unchecked") - @Override - public T answer(InvocationOnMock invocationOnMock) throws Throwable { - T result = (T) invocationOnMock.callRealMethod(); - synchronized (this.results) { - results.add(result); - } - long wait = longSupplier.getAsLong(); - if (wait > 0) { - Thread.sleep(wait); - } - return result; - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/SmokeTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/SmokeTest.java deleted file mode 100644 index f5c99731471c8..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/SmokeTest.java +++ /dev/null @@ -1,1057 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assumptions.*; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketImpl; -import java.net.SocketImplFactory; -import java.net.SocketOption; -import java.net.StandardSocketOptions; -import java.net.UnknownHostException; -import java.util.BitSet; -import java.util.Optional; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.commons.lang.StringUtils; -import org.eclipse.jdt.annotation.NonNull; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusResponse; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; -import org.openhab.io.transport.modbus.exception.ModbusConnectionException; -import org.openhab.io.transport.modbus.exception.ModbusSlaveErrorResponseException; -import org.openhab.io.transport.modbus.exception.ModbusSlaveIOException; -import org.slf4j.LoggerFactory; - -import net.wimpi.modbus.msg.ModbusRequest; -import net.wimpi.modbus.msg.WriteCoilRequest; -import net.wimpi.modbus.msg.WriteMultipleCoilsRequest; -import net.wimpi.modbus.procimg.SimpleDigitalIn; -import net.wimpi.modbus.procimg.SimpleDigitalOut; -import net.wimpi.modbus.procimg.SimpleRegister; -import net.wimpi.modbus.util.BitVector; - -/** - * @author Sami Salonen - Initial contribution - */ -public class SmokeTest extends IntegrationTestSupport { - - private static final int COIL_EVERY_N_TRUE = 2; - private static final int DISCRETE_EVERY_N_TRUE = 3; - private static final int HOLDING_REGISTER_MULTIPLIER = 1; - private static final int INPUT_REGISTER_MULTIPLIER = 10; - private static final SpyingSocketFactory socketSpy = new SpyingSocketFactory(); - static { - try { - Socket.setSocketImplFactory(socketSpy); - } catch (IOException e) { - fail("Could not install socket spy in SmokeTest"); - } - } - - /** - * Whether tests are run in Continuous Integration environment, i.e. Jenkins or Travis CI - * - * Travis CI is detected using CI environment variable, see https://docs.travis-ci.com/user/environment-variables/ - * Jenkins CI is detected using JENKINS_HOME environment variable - * - * @return - */ - private boolean isRunningInCI() { - return "true".equals(System.getenv("CI")) || StringUtils.isNotBlank(System.getenv("JENKINS_HOME")); - } - - private void generateData() { - for (int i = 0; i < 100; i++) { - spi.addRegister(new SimpleRegister(i * HOLDING_REGISTER_MULTIPLIER)); - spi.addInputRegister(new SimpleRegister(i * INPUT_REGISTER_MULTIPLIER)); - spi.addDigitalOut(new SimpleDigitalOut(i % COIL_EVERY_N_TRUE == 0)); - spi.addDigitalIn(new SimpleDigitalIn(i % DISCRETE_EVERY_N_TRUE == 0)); - } - } - - private void testCoilValues(BitArray bits, int offsetInBitArray) { - for (int i = 0; i < bits.size(); i++) { - boolean expected = (i + offsetInBitArray) % COIL_EVERY_N_TRUE == 0; - assertThat(String.format("i=%d, expecting %b, got %b", i, bits.getBit(i), expected), bits.getBit(i), - is(equalTo(expected))); - } - } - - private void testDiscreteValues(BitArray bits, int offsetInBitArray) { - for (int i = 0; i < bits.size(); i++) { - boolean expected = (i + offsetInBitArray) % DISCRETE_EVERY_N_TRUE == 0; - assertThat(String.format("i=%d, expecting %b, got %b", i, bits.getBit(i), expected), bits.getBit(i), - is(equalTo(expected))); - } - } - - private void testHoldingValues(ModbusRegisterArray registers, int offsetInRegisters) { - for (int i = 0; i < registers.size(); i++) { - int expected = (i + offsetInRegisters) * HOLDING_REGISTER_MULTIPLIER; - assertThat(String.format("i=%d, expecting %d, got %d", i, registers.getRegister(i), expected), - registers.getRegister(i), is(equalTo(expected))); - } - } - - private void testInputValues(ModbusRegisterArray registers, int offsetInRegisters) { - for (int i = 0; i < registers.size(); i++) { - int expected = (i + offsetInRegisters) * INPUT_REGISTER_MULTIPLIER; - assertThat(String.format("i=%d, expecting %d, got %d", i, registers.getRegister(i), expected), - registers.getRegister(i), is(equalTo(expected))); - } - } - - @BeforeEach - public void setUpSocketSpy() throws IOException { - socketSpy.sockets.clear(); - } - - /** - * Test handling of slave error responses. In this case, error code = 2, illegal data address, since no data. - * - * @throws Exception - */ - @Test - public void testSlaveReadErrorResponse() throws Exception { - ModbusSlaveEndpoint endpoint = getEndpoint(); - AtomicInteger okCount = new AtomicInteger(); - AtomicInteger errorCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastError = new AtomicReference<>(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 0, 5, 1), result -> { - assert result.getRegisters().isPresent(); - okCount.incrementAndGet(); - callbackCalled.countDown(); - }, failure -> { - errorCount.incrementAndGet(); - lastError.set(failure.getCause()); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(okCount.get(), is(equalTo(0))); - assertThat(errorCount.get(), is(equalTo(1))); - assertTrue(lastError.get() instanceof ModbusSlaveErrorResponseException, lastError.toString()); - } - } - - /** - * Test handling of connection error responses. - * - * @throws Exception - */ - @Test - public void testSlaveConnectionError() throws Exception { - // In the test we have non-responding slave (see http://stackoverflow.com/a/904609), and we use short connection - // timeout - ModbusSlaveEndpoint endpoint = new ModbusTCPSlaveEndpoint("10.255.255.1", 9999); - EndpointPoolConfiguration configuration = new EndpointPoolConfiguration(); - configuration.setConnectTimeoutMillis(100); - - AtomicInteger okCount = new AtomicInteger(); - AtomicInteger errorCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastError = new AtomicReference<>(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, - configuration)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 0, 5, 1), result -> { - assert result.getRegisters().isPresent(); - okCount.incrementAndGet(); - callbackCalled.countDown(); - }, failure -> { - errorCount.incrementAndGet(); - lastError.set(failure.getCause()); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(okCount.get(), is(equalTo(0))); - assertThat(errorCount.get(), is(equalTo(1))); - assertTrue(lastError.get() instanceof ModbusConnectionException, lastError.toString()); - } - } - - /** - * Have super slow connection response, eventually resulting as timeout (due to default timeout of 3 s in - * net.wimpi.modbus.Modbus.DEFAULT_TIMEOUT) - * - * @throws Exception - */ - @Test - public void testIOError() throws Exception { - artificialServerWait = 60000; - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger okCount = new AtomicInteger(); - AtomicInteger errorCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastError = new AtomicReference<>(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 0, 5, 1), result -> { - assert result.getRegisters().isPresent(); - okCount.incrementAndGet(); - callbackCalled.countDown(); - }, failure -> { - errorCount.incrementAndGet(); - lastError.set(failure.getCause()); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(15, TimeUnit.SECONDS)); - assertThat(okCount.get(), is(equalTo(0))); - assertThat(lastError.toString(), errorCount.get(), is(equalTo(1))); - assertTrue(lastError.get() instanceof ModbusSlaveIOException, lastError.toString()); - } - } - - public void testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode functionCode, int count) throws Exception { - assertThat(functionCode, is(anyOf(equalTo(ModbusReadFunctionCode.READ_INPUT_DISCRETES), - equalTo(ModbusReadFunctionCode.READ_COILS)))); - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastData = new AtomicReference<>(); - - final int offset = 1; - - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, functionCode, offset, count, 1), - result -> { - Optional<@NonNull BitArray> bitsOptional = result.getBits(); - if (bitsOptional.isPresent()) { - lastData.set(bitsOptional.get()); - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - BitArray bits = (BitArray) lastData.get(); - assertThat(bits, notNullValue()); - assertThat(bits.size(), is(equalTo(count))); - if (functionCode == ModbusReadFunctionCode.READ_INPUT_DISCRETES) { - testDiscreteValues(bits, offset); - } else { - testCoilValues(bits, offset); - } - } - } - - @Test - public void testOneOffReadWithDiscrete1() throws Exception { - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_INPUT_DISCRETES, 1); - } - - @Test - public void testOneOffReadWithDiscrete7() throws Exception { - // less than byte - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_INPUT_DISCRETES, 7); - } - - @Test - public void testOneOffReadWithDiscrete8() throws Exception { - // exactly one byte - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_INPUT_DISCRETES, 8); - } - - @Test - public void testOneOffReadWithDiscrete13() throws Exception { - // larger than byte, less than word (16 bit) - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_INPUT_DISCRETES, 13); - } - - @Test - public void testOneOffReadWithDiscrete18() throws Exception { - // larger than word (16 bit) - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_INPUT_DISCRETES, 18); - } - - @Test - public void testOneOffReadWithCoils1() throws Exception { - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_COILS, 1); - } - - @Test - public void testOneOffReadWithCoils7() throws Exception { - // less than byte - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_COILS, 7); - } - - @Test - public void testOneOffReadWithCoils8() throws Exception { - // exactly one byte - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_COILS, 8); - } - - @Test - public void testOneOffReadWithCoils13() throws Exception { - // larger than byte, less than word (16 bit) - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_COILS, 13); - } - - @Test - public void testOneOffReadWithCoils18() throws Exception { - // larger than word (16 bit) - testOneOffReadWithDiscreteOrCoils(ModbusReadFunctionCode.READ_COILS, 18); - } - - /** - * - * @throws Exception - */ - @Test - public void testOneOffReadWithHolding() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastData = new AtomicReference<>(); - - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 1, 15, 1), result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - lastData.set(registersOptional.get()); - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - ModbusRegisterArray registers = (ModbusRegisterArray) lastData.get(); - assertThat(registers.size(), is(equalTo(15))); - testHoldingValues(registers, 1); - } - } - - /** - * - * @throws Exception - */ - @Test - public void testOneOffReadWithInput() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastData = new AtomicReference<>(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_INPUT_REGISTERS, 1, 15, 1), result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - lastData.set(registersOptional.get()); - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - ModbusRegisterArray registers = (ModbusRegisterArray) lastData.get(); - assertThat(registers.size(), is(equalTo(15))); - testInputValues(registers, 1); - } - } - - /** - * - * @throws Exception - */ - @Test - public void testOneOffWriteMultipleCoil() throws Exception { - LoggerFactory.getLogger(this.getClass()).error("STARTING MULTIPLE"); - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - AtomicReference lastData = new AtomicReference<>(); - - BitArray bits = new BitArray(true, true, false, false, true, true); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimeWrite(new ModbusWriteCoilRequestBlueprint(SLAVE_UNIT_ID, 3, bits, true, 1), result -> { - lastData.set(result.getResponse()); - }, failure -> { - unexpectedCount.incrementAndGet(); - }); - waitForAssert(() -> { - assertThat(unexpectedCount.get(), is(equalTo(0))); - assertThat(lastData.get(), is(notNullValue())); - - ModbusResponse response = (ModbusResponse) lastData.get(); - assertThat(response.getFunctionCode(), is(equalTo(15))); - - assertThat(modbustRequestCaptor.getAllReturnValues().size(), is(equalTo(1))); - ModbusRequest request = modbustRequestCaptor.getAllReturnValues().get(0); - assertThat(request.getFunctionCode(), is(equalTo(15))); - assertThat(((WriteMultipleCoilsRequest) request).getReference(), is(equalTo(3))); - assertThat(((WriteMultipleCoilsRequest) request).getBitCount(), is(equalTo(bits.size()))); - BitVector writeRequestCoils = ((WriteMultipleCoilsRequest) request).getCoils(); - BitArray writtenBits = new BitArray(BitSet.valueOf(writeRequestCoils.getBytes()), bits.size()); - assertThat(writtenBits, is(equalTo(bits))); - }, 6000, 10); - } - LoggerFactory.getLogger(this.getClass()).error("ENDINGMULTIPLE"); - } - - /** - * Write is out-of-bounds, slave should return error - * - * @throws Exception - */ - @Test - public void testOneOffWriteMultipleCoilError() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastError = new AtomicReference<>(); - - BitArray bits = new BitArray(500); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimeWrite(new ModbusWriteCoilRequestBlueprint(SLAVE_UNIT_ID, 3, bits, true, 1), result -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }, failure -> { - lastError.set(failure.getCause()); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - assertTrue(lastError.get() instanceof ModbusSlaveErrorResponseException, lastError.toString()); - - assertThat(modbustRequestCaptor.getAllReturnValues().size(), is(equalTo(1))); - ModbusRequest request = modbustRequestCaptor.getAllReturnValues().get(0); - assertThat(request.getFunctionCode(), is(equalTo(15))); - assertThat(((WriteMultipleCoilsRequest) request).getReference(), is(equalTo(3))); - assertThat(((WriteMultipleCoilsRequest) request).getBitCount(), is(equalTo(bits.size()))); - BitVector writeRequestCoils = ((WriteMultipleCoilsRequest) request).getCoils(); - BitArray writtenBits = new BitArray(BitSet.valueOf(writeRequestCoils.getBytes()), bits.size()); - assertThat(writtenBits, is(equalTo(bits))); - } - } - - /** - * - * @throws Exception - */ - @Test - public void testOneOffWriteSingleCoil() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastData = new AtomicReference<>(); - - BitArray bits = new BitArray(true); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimeWrite(new ModbusWriteCoilRequestBlueprint(SLAVE_UNIT_ID, 3, bits, false, 1), result -> { - lastData.set(result.getResponse()); - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - ModbusResponse response = (ModbusResponse) lastData.get(); - assertThat(response.getFunctionCode(), is(equalTo(5))); - - assertThat(modbustRequestCaptor.getAllReturnValues().size(), is(equalTo(1))); - ModbusRequest request = modbustRequestCaptor.getAllReturnValues().get(0); - assertThat(request.getFunctionCode(), is(equalTo(5))); - assertThat(((WriteCoilRequest) request).getReference(), is(equalTo(3))); - assertThat(((WriteCoilRequest) request).getCoil(), is(equalTo(true))); - } - } - - /** - * - * Write is out-of-bounds, slave should return error - * - * @throws Exception - */ - @Test - public void testOneOffWriteSingleCoilError() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicReference lastError = new AtomicReference<>(); - - BitArray bits = new BitArray(true); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.submitOneTimeWrite(new ModbusWriteCoilRequestBlueprint(SLAVE_UNIT_ID, 300, bits, false, 1), - result -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }, failure -> { - lastError.set(failure.getCause()); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - assertThat(unexpectedCount.get(), is(equalTo(0))); - assertTrue(lastError.get() instanceof ModbusSlaveErrorResponseException, lastError.toString()); - - assertThat(modbustRequestCaptor.getAllReturnValues().size(), is(equalTo(1))); - ModbusRequest request = modbustRequestCaptor.getAllReturnValues().get(0); - assertThat(request.getFunctionCode(), is(equalTo(5))); - assertThat(((WriteCoilRequest) request).getReference(), is(equalTo(300))); - assertThat(((WriteCoilRequest) request).getCoil(), is(equalTo(true))); - } - } - - /** - * Testing regular polling of coils - * - * Amount of requests is timed, and average poll period is checked - * - * @throws Exception - */ - @Test - public void testRegularReadEvery150msWithCoil() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(5); - AtomicInteger dataReceived = new AtomicInteger(); - - long start = System.currentTimeMillis(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.registerRegularPoll( - new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, ModbusReadFunctionCode.READ_COILS, 1, 15, 1), 150, 0, - result -> { - Optional<@NonNull BitArray> bitsOptional = result.getBits(); - if (bitsOptional.isPresent()) { - BitArray bits = bitsOptional.get(); - dataReceived.incrementAndGet(); - try { - assertThat(bits.size(), is(equalTo(15))); - testCoilValues(bits, 1); - } catch (AssertionError e) { - unexpectedCount.incrementAndGet(); - } - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - - long end = System.currentTimeMillis(); - assertPollDetails(unexpectedCount, dataReceived, start, end, 145, 500); - } - } - - /** - * Testing regular polling of holding registers - * - * Amount of requests is timed, and average poll period is checked - * - * @throws Exception - */ - @Test - public void testRegularReadEvery150msWithHolding() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(5); - AtomicInteger dataReceived = new AtomicInteger(); - - long start = System.currentTimeMillis(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.registerRegularPoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 1, 15, 1), 150, 0, result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - ModbusRegisterArray registers = registersOptional.get(); - dataReceived.incrementAndGet(); - try { - assertThat(registers.size(), is(equalTo(15))); - testHoldingValues(registers, 1); - } catch (AssertionError e) { - unexpectedCount.incrementAndGet(); - } - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - long end = System.currentTimeMillis(); - assertPollDetails(unexpectedCount, dataReceived, start, end, 145, 500); - } - } - - @Test - public void testRegularReadFirstErrorThenOK() throws Exception { - generateData(); - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(5); - AtomicInteger dataReceived = new AtomicInteger(); - - long start = System.currentTimeMillis(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.registerRegularPoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 1, 15, 1), 150, 0, result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - ModbusRegisterArray registers = registersOptional.get(); - dataReceived.incrementAndGet(); - try { - assertThat(registers.size(), is(equalTo(15))); - testHoldingValues(registers, 1); - } catch (AssertionError e) { - unexpectedCount.incrementAndGet(); - } - - } else { - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - unexpectedCount.incrementAndGet(); - callbackCalled.countDown(); - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - long end = System.currentTimeMillis(); - assertPollDetails(unexpectedCount, dataReceived, start, end, 145, 500); - } - } - - /** - * - * @param unexpectedCount number of unexpected callback calls - * @param callbackCalled number of callback calls (including unexpected) - * @param dataReceived number of expected callback calls (onBits or onRegisters) - * @param pollStartMillis poll start time in milliepoch - * @param expectedPollAverageMin average poll period should be at least greater than this - * @param expectedPollAverageMax average poll period less than this - * @throws InterruptedException - */ - private void assertPollDetails(AtomicInteger unexpectedCount, AtomicInteger expectedCount, long pollStartMillis, - long pollEndMillis, int expectedPollAverageMin, int expectedPollAverageMax) throws InterruptedException { - int responses = expectedCount.get(); - assertThat(unexpectedCount.get(), is(equalTo(0))); - assertTrue(responses > 1); - - // Rest of the (timing-sensitive) assertions are not run in CI - assumeFalse(isRunningInCI(), "Running in CI! Will not test timing-sensitive details"); - float averagePollPeriodMillis = ((float) (pollEndMillis - pollStartMillis)) / (responses - 1); - assertTrue(averagePollPeriodMillis > expectedPollAverageMin && averagePollPeriodMillis < expectedPollAverageMax, - String.format( - "Measured avarage poll period %f ms (%d responses in %d ms) is not withing expected limits [%d, %d]", - averagePollPeriodMillis, responses, pollEndMillis - pollStartMillis, expectedPollAverageMin, - expectedPollAverageMax)); - } - - @Test - public void testUnregisterPollingOnClose() throws Exception { - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - AtomicInteger errorCount = new AtomicInteger(); - CountDownLatch successfulCountDownLatch = new CountDownLatch(3); - AtomicInteger expectedReceived = new AtomicInteger(); - - long start = System.currentTimeMillis(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - comms.registerRegularPoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 1, 15, 1), 200, 0, result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - expectedReceived.incrementAndGet(); - successfulCountDownLatch.countDown(); - } else { - // bits - unexpectedCount.incrementAndGet(); - } - }, failure -> { - if (spi.getDigitalInCount() > 0) { - // No errors expected after server filled with data - unexpectedCount.incrementAndGet(); - } else { - expectedReceived.incrementAndGet(); - errorCount.incrementAndGet(); - generateData(); - successfulCountDownLatch.countDown(); - } - }); - // Wait for N successful responses before proceeding with assertions of poll rate - assertTrue(successfulCountDownLatch.await(60, TimeUnit.SECONDS)); - - long end = System.currentTimeMillis(); - assertPollDetails(unexpectedCount, expectedReceived, start, end, 190, 600); - - // wait some more and ensure nothing comes back - Thread.sleep(500); - assertThat(unexpectedCount.get(), is(equalTo(0))); - } - } - - @Test - public void testUnregisterPollingExplicit() throws Exception { - ModbusSlaveEndpoint endpoint = getEndpoint(); - - AtomicInteger unexpectedCount = new AtomicInteger(); - AtomicInteger errorCount = new AtomicInteger(); - CountDownLatch callbackCalled = new CountDownLatch(3); - AtomicInteger expectedReceived = new AtomicInteger(); - - long start = System.currentTimeMillis(); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) { - PollTask task = comms.registerRegularPoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, - ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 1, 15, 1), 200, 0, result -> { - Optional<@NonNull ModbusRegisterArray> registersOptional = result.getRegisters(); - if (registersOptional.isPresent()) { - expectedReceived.incrementAndGet(); - } else { - // bits - unexpectedCount.incrementAndGet(); - } - callbackCalled.countDown(); - }, failure -> { - if (spi.getDigitalInCount() > 0) { - // No errors expected after server filled with data - unexpectedCount.incrementAndGet(); - } else { - expectedReceived.incrementAndGet(); - errorCount.incrementAndGet(); - generateData(); - } - }); - assertTrue(callbackCalled.await(60, TimeUnit.SECONDS)); - long end = System.currentTimeMillis(); - assertPollDetails(unexpectedCount, expectedReceived, start, end, 190, 600); - - // Explicitly unregister the regular poll - comms.unregisterRegularPoll(task); - - // wait some more and ensure nothing comes back - Thread.sleep(500); - assertThat(unexpectedCount.get(), is(equalTo(0))); - } - } - - @SuppressWarnings("null") - @Test - public void testPoolConfigurationWithoutListener() throws Exception { - EndpointPoolConfiguration defaultConfig = modbusManager.getEndpointPoolConfiguration(getEndpoint()); - assertThat(defaultConfig, is(notNullValue())); - - EndpointPoolConfiguration newConfig = new EndpointPoolConfiguration(); - newConfig.setConnectMaxTries(5); - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(getEndpoint(), - newConfig)) { - // Sets configuration for the endpoint implicitly - } - - assertThat(modbusManager.getEndpointPoolConfiguration(getEndpoint()).getConnectMaxTries(), is(equalTo(5))); - assertThat(modbusManager.getEndpointPoolConfiguration(getEndpoint()), is(not(equalTo(defaultConfig)))); - - // Reset config - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(getEndpoint(), null)) { - // Sets configuration for the endpoint implicitly - } - // Should match the default - assertThat(modbusManager.getEndpointPoolConfiguration(getEndpoint()), is(equalTo(defaultConfig))); - } - - @Test - public void testConnectionCloseAfterLastCommunicationInterfaceClosed() throws IllegalArgumentException, Exception { - assumeFalse(isRunningInCI(), "Running in CI! Will not test timing-sensitive details"); - ModbusSlaveEndpoint endpoint = getEndpoint(); - assumeTrue(endpoint instanceof ModbusTCPSlaveEndpoint, - "Connection closing test supported only with TCP slaves"); - - // Generate server data - generateData(); - - EndpointPoolConfiguration config = new EndpointPoolConfiguration(); - config.setReconnectAfterMillis(9_000_000); - - // 1. capture open connections at this point - long openSocketsBefore = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsBefore, is(equalTo(0L))); - - // 2. make poll, binding opens the tcp connection - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, config)) { - { - CountDownLatch latch = new CountDownLatch(1); - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(1, ModbusReadFunctionCode.READ_COILS, 0, 1, 1), - response -> { - latch.countDown(); - }, failure -> { - latch.countDown(); - }); - assertTrue(latch.await(60, TimeUnit.SECONDS)); - } - waitForAssert(() -> { - // 3. ensure one open connection - long openSocketsAfter = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsAfter, is(equalTo(1L))); - }); - try (ModbusCommunicationInterface comms2 = modbusManager.newModbusCommunicationInterface(endpoint, - config)) { - { - CountDownLatch latch = new CountDownLatch(1); - comms.submitOneTimePoll( - new ModbusReadRequestBlueprint(1, ModbusReadFunctionCode.READ_COILS, 0, 1, 1), response -> { - latch.countDown(); - }, failure -> { - latch.countDown(); - }); - assertTrue(latch.await(60, TimeUnit.SECONDS)); - } - assertThat(getNumberOfOpenClients(socketSpy), is(equalTo(1L))); - // wait for moment (to check that no connections are closed) - Thread.sleep(1000); - // no more than 1 connection, even though requests are going through - assertThat(getNumberOfOpenClients(socketSpy), is(equalTo(1L))); - } - Thread.sleep(1000); - // Still one connection open even after closing second connection - assertThat(getNumberOfOpenClients(socketSpy), is(equalTo(1L))); - - } // 4. close (the last) comms - // ensure that open connections are closed - // (despite huge "reconnect after millis") - waitForAssert(() -> { - long openSocketsAfterClose = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsAfterClose, is(equalTo(0L))); - }); - } - - @Test - public void testConnectionCloseAfterOneOffPoll() throws IllegalArgumentException, Exception { - assumeFalse(isRunningInCI(), "Running in CI! Will not test timing-sensitive details"); - ModbusSlaveEndpoint endpoint = getEndpoint(); - assumeTrue(endpoint instanceof ModbusTCPSlaveEndpoint, - "Connection closing test supported only with TCP slaves"); - - // Generate server data - generateData(); - - EndpointPoolConfiguration config = new EndpointPoolConfiguration(); - config.setReconnectAfterMillis(2_000); - - // 1. capture open connections at this point - long openSocketsBefore = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsBefore, is(equalTo(0L))); - - // 2. make poll, binding opens the tcp connection - try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, config)) { - { - CountDownLatch latch = new CountDownLatch(1); - comms.submitOneTimePoll(new ModbusReadRequestBlueprint(1, ModbusReadFunctionCode.READ_COILS, 0, 1, 1), - response -> { - latch.countDown(); - }, failure -> { - latch.countDown(); - }); - assertTrue(latch.await(60, TimeUnit.SECONDS)); - } - // Right after the poll we should have one connection open - waitForAssert(() -> { - // 3. ensure one open connection - long openSocketsAfter = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsAfter, is(equalTo(1L))); - }); - // 4. Connection should close itself by the commons pool eviction policy (checking for old idle connection - // every now and then) - waitForAssert(() -> { - // 3. ensure one open connection - long openSocketsAfter = getNumberOfOpenClients(socketSpy); - assertThat(openSocketsAfter, is(equalTo(0L))); - }, 60_000, 50); - - } - } - - private long getNumberOfOpenClients(SpyingSocketFactory socketSpy) { - final InetAddress testServerAddress; - try { - testServerAddress = localAddress(); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - return socketSpy.sockets.stream().filter(this::isConnectedToTestServer).count(); - } - - /** - * Spy all sockets that are created - * - * @author Sami Salonen - * - */ - private static class SpyingSocketFactory implements SocketImplFactory { - - Queue sockets = new ConcurrentLinkedQueue(); - - @Override - public SocketImpl createSocketImpl() { - SocketImpl socket = newSocksSocketImpl(); - sockets.add(socket); - return socket; - } - } - - private static SocketImpl newSocksSocketImpl() { - try { - Class socksSocketImplClass = Class.forName("java.net.SocksSocketImpl"); - Class socketImplClass = SocketImpl.class; - - // // For Debugging - // for (Method method : socketImplClass.getDeclaredMethods()) { - // LoggerFactory.getLogger("foobar") - // .error("SocketImpl." + method.getName() + Arrays.toString(method.getParameters())); - // } - // for (Constructor constructor : socketImplClass.getDeclaredConstructors()) { - // LoggerFactory.getLogger("foobar") - // .error("SocketImpl." + constructor.getName() + Arrays.toString(constructor.getParameters())); - // } - // for (Method method : socksSocketImplClass.getDeclaredMethods()) { - // LoggerFactory.getLogger("foobar") - // .error("SocksSocketImpl." + method.getName() + Arrays.toString(method.getParameters())); - // } - // for (Constructor constructor : socksSocketImplClass.getDeclaredConstructors()) { - // LoggerFactory.getLogger("foobar").error( - // "SocksSocketImpl." + constructor.getName() + Arrays.toString(constructor.getParameters())); - // } - - try { - Constructor constructor = socksSocketImplClass.getDeclaredConstructor(); - constructor.setAccessible(true); - return (SocketImpl) constructor.newInstance(); - } catch (NoSuchMethodException e) { - // Newer Javas (Java 14->) do not have default constructor 'SocksSocketImpl()' - // Instead we use "static SocketImpl.createPlatformSocketImpl" and "SocksSocketImpl(SocketImpl) - Method socketImplCreateMethod = socketImplClass.getDeclaredMethod("createPlatformSocketImpl", - boolean.class); - socketImplCreateMethod.setAccessible(true); - Object socketImpl = socketImplCreateMethod.invoke(/* null since we deal with static method */ null, - /* server */false); - - Constructor socksSocketImplConstructor = socksSocketImplClass - .getDeclaredConstructor(socketImplClass); - socksSocketImplConstructor.setAccessible(true); - return (SocketImpl) socksSocketImplConstructor.newInstance(socketImpl); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private boolean isConnectedToTestServer(SocketImpl impl) { - final InetAddress testServerAddress; - try { - testServerAddress = localAddress(); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - - final int port; - boolean connected = true; - final InetAddress address; - try { - Method getPort = SocketImpl.class.getDeclaredMethod("getPort"); - getPort.setAccessible(true); - port = (int) getPort.invoke(impl); - - Method getInetAddressMethod = SocketImpl.class.getDeclaredMethod("getInetAddress"); - getInetAddressMethod.setAccessible(true); - address = (InetAddress) getInetAddressMethod.invoke(impl); - - // hacky (but java8-14 compatible) way to know if socket is open - // SocketImpl.getOption throws IOException when socket is closed - Method getOption = SocketImpl.class.getDeclaredMethod("getOption", SocketOption.class); - getOption.setAccessible(true); - try { - getOption.invoke(impl, StandardSocketOptions.SO_KEEPALIVE); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof IOException) { - connected = false; - } else { - throw e; - } - } - } catch (InvocationTargetException | SecurityException | IllegalArgumentException | IllegalAccessException - | NoSuchMethodException e) { - throw new RuntimeException(e); - } - return port == tcpModbusPort && connected && address.equals(testServerAddress); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ValueBufferTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ValueBufferTest.java deleted file mode 100644 index 7f14c137add8a..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/ValueBufferTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.junit.jupiter.api.Assertions.*; - -import java.nio.BufferOverflowException; -import java.nio.InvalidMarkException; - -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.ValueBuffer; - -/** - * @author Sami Salonen - Initial contribution - */ -public class ValueBufferTest { - - @Test - public void testInt32Int8() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - assertEquals(7, wrap.remaining()); - assertTrue(wrap.hasRemaining()); - - assertEquals(-1004, wrap.getSInt32()); - assertEquals(3, wrap.remaining()); - assertTrue(wrap.hasRemaining()); - - assertEquals(3, wrap.getSInt8()); - assertEquals(2, wrap.remaining()); - assertTrue(wrap.hasRemaining()); - - assertEquals(-1, wrap.getSInt8()); - assertEquals(1, wrap.remaining()); - assertTrue(wrap.hasRemaining()); - - assertEquals(254, wrap.getUInt8()); - assertEquals(0, wrap.remaining()); - assertFalse(wrap.hasRemaining()); - } - - @Test - public void testOutOfBounds() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - wrap.position(7); - assertThrows(IllegalArgumentException.class, () -> wrap.getSInt8()); - } - - @Test - public void testOutOfBound2s() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - wrap.position(6); - assertThrows(IllegalArgumentException.class, () -> wrap.getSInt16()); - } - - @Test - public void testMarkReset() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - wrap.mark(); - assertEquals(-1004, wrap.getSInt32()); - wrap.reset(); - assertEquals(4294966292L, wrap.getUInt32()); - wrap.mark(); - assertEquals(3, wrap.getSInt8()); - wrap.reset(); - assertEquals(3, wrap.getSInt8()); - assertEquals(-1, wrap.getSInt8()); - assertEquals(254, wrap.getUInt8()); - } - - @Test - public void testMarkHigherThanPosition() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - assertEquals(-1004, wrap.getSInt32()); - wrap.position(4); - wrap.mark(); - assertEquals(4, wrap.position()); - - // mark = position - wrap.position(4); - assertEquals(4, wrap.position()); - wrap.reset(); - assertEquals(4, wrap.position()); - - // position < mark - wrap.position(3); // Mark is removed here - assertEquals(3, wrap.position()); - boolean caughtException = false; - try { - wrap.reset(); - } catch (InvalidMarkException e) { - // OK, expected - caughtException = true; - } - assertTrue(caughtException); - assertEquals(3, wrap.position()); - - // Mark is removed. Reset unaccessible even with original position of 4 - wrap.position(4); - assertEquals(4, wrap.position()); - caughtException = false; - try { - wrap.reset(); - } catch (InvalidMarkException e) { - // OK, expected - caughtException = true; - } - assertTrue(caughtException); - } - - @Test - public void testMarkLowerThanPosition() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFC, 0x14, 3, -1, -2 }); - assertEquals(-1004, wrap.getSInt32()); - wrap.position(4); - wrap.mark(); - assertEquals(4, wrap.position()); - - // mark = position - wrap.position(4); - assertEquals(4, wrap.position()); - wrap.reset(); - assertEquals(4, wrap.position()); - - // mark > position - wrap.position(6); - assertEquals(6, wrap.position()); - wrap.reset(); - assertEquals(4, wrap.position()); - } - - @Test - public void testPosition() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { 0, 0, 0, 1, 3, -1, -2 }); - assertEquals(0, wrap.position()); - - wrap.position(4); - assertEquals(4, wrap.position()); - assertEquals(3, wrap.getSInt8()); - assertEquals(5, wrap.position()); - } - - @Test - public void testBulkGetBufferOverflow() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { 0, 0 }); - byte[] threeBytes = new byte[3]; - assertThrows(BufferOverflowException.class, () -> wrap.get(threeBytes)); - } - - @Test - public void testBulkGetAtCapacity() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { 1, 2 }); - byte[] twoBytes = new byte[2]; - wrap.get(twoBytes); - assertEquals(1, twoBytes[0]); - assertEquals(2, twoBytes[1]); - assertEquals(2, wrap.position()); - assertFalse(wrap.hasRemaining()); - } - - @Test - public void testBulkGet() { - ValueBuffer wrap = ValueBuffer.wrap(new byte[] { 1, 2, 3 }); - byte[] onebyte = new byte[1]; - wrap.get(onebyte); - assertEquals(1, onebyte[0]); - assertEquals(1, wrap.position()); - - // non-zero position - byte[] twoBytes = new byte[2]; - wrap.position(1); - wrap.get(twoBytes); - assertEquals(2, twoBytes[0]); - assertEquals(3, twoBytes[1]); - assertEquals(3, wrap.position()); - } -} diff --git a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/WriteRequestJsonUtilitiesTest.java b/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/WriteRequestJsonUtilitiesTest.java deleted file mode 100644 index 22fa4023097ad..0000000000000 --- a/bundles/org.openhab.io.transport.modbus/src/test/java/org/openhab/io/transport/modbus/test/WriteRequestJsonUtilitiesTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.io.transport.modbus.test; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.ArrayMatching.arrayContaining; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.openhab.io.transport.modbus.ModbusConstants.*; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.eclipse.jdt.annotation.NonNull; -import org.hamcrest.Matcher; -import org.junit.jupiter.api.Test; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.json.WriteRequestJsonUtilities; - -/** - * @author Sami Salonen - Initial contribution - */ -public class WriteRequestJsonUtilitiesTest { - - private static List MAX_REGISTERS = IntStream.range(0, MAX_REGISTERS_WRITE_COUNT).mapToObj(i -> "1") - .collect(Collectors.toList()); - private static List OVER_MAX_REGISTERS = IntStream.range(0, MAX_REGISTERS_WRITE_COUNT + 1) - .mapToObj(i -> "1").collect(Collectors.toList()); - - private static List MAX_COILS = IntStream.range(0, MAX_BITS_WRITE_COUNT).mapToObj(i -> "1") - .collect(Collectors.toList()); - private static List OVER_MAX_COILS = IntStream.range(0, MAX_BITS_WRITE_COUNT + 1).mapToObj(i -> "1") - .collect(Collectors.toList()); - - @Test - public void testEmptyArray() { - assertThat(WriteRequestJsonUtilities.fromJson(3, "[]").size(), is(equalTo(0))); - } - - @Test - public void testFC6NoRegister() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 6,"// - + "\"address\": 5412,"// - + "\"value\": []"// - + "}]")); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC6SingleRegister() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 6,"// - + "\"address\": 5412,"// - + "\"value\": [3]"// - + "}]").toArray(), - arrayContaining((Matcher) new RegisterMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_SINGLE_REGISTER, 3))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC6SingleRegisterMaxTries99() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 6,"// - + "\"address\": 5412,"// - + "\"value\": [3],"// - + "\"maxTries\": 99"// - + "}]").toArray(), - arrayContaining( - (Matcher) new RegisterMatcher(55, 5412, 99, ModbusWriteFunctionCode.WRITE_SINGLE_REGISTER, 3))); - } - - @Test - public void testFC6MultipleRegisters() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 6,"// - + "\"address\": 5412,"// - + "\"value\": [3, 4]"// - + "}]")); - } - - @Test - public void testFC16NoRegister() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 16,"// - + "\"address\": 5412,"// - + "\"value\": []"// - + "}]")); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC16SingleRegister() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 16,"// - + "\"address\": 5412,"// - + "\"value\": [3]"// - + "}]").toArray(), - arrayContaining((Matcher) new RegisterMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_MULTIPLE_REGISTERS, 3))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC16MultipleRegisters() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 16,"// - + "\"address\": 5412,"// - + "\"value\": [3, 4, 2]"// - + "}]").toArray(), - arrayContaining((Matcher) new RegisterMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_MULTIPLE_REGISTERS, 3, 4, 2))); - } - - @Test - public void testFC16MultipleRegistersMaxRegisters() { - Collection<@NonNull ModbusWriteRequestBlueprint> writes = WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 16,"// - + "\"address\": 5412,"// - + "\"value\": [" + String.join(",", MAX_REGISTERS) + "]"// - + "}]"); - assertThat(writes.size(), is(equalTo(1))); - } - - @Test - public void testFC16MultipleRegistersTooManyRegisters() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 16,"// - + "\"address\": 5412,"// - + "\"value\": [" + String.join(",", OVER_MAX_REGISTERS) + "]"// - + "}]")); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC5SingeCoil() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 5,"// - + "\"address\": 5412,"// - + "\"value\": [3]" // value 3 (!= 0) is converted to boolean true - + "}]").toArray(), - arrayContaining((Matcher) new CoilMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_COIL, true))); - } - - @Test - public void testFC5MultipleCoils() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 5,"// - + "\"address\": 5412,"// - + "\"value\": [3, 4]"// - + "}]")); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC15SingleCoil() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 15,"// - + "\"address\": 5412,"// - + "\"value\": [3]"// - + "}]").toArray(), - arrayContaining((Matcher) new CoilMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS, true))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testFC15MultipleCoils() { - assertThat(WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 15,"// - + "\"address\": 5412,"// - + "\"value\": [1, 0, 5]"// - + "}]").toArray(), - arrayContaining((Matcher) new CoilMatcher(55, 5412, WriteRequestJsonUtilities.DEFAULT_MAX_TRIES, - ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS, true, false, true))); - } - - @Test - public void testFC15MultipleCoilsMaxCoils() { - Collection<@NonNull ModbusWriteRequestBlueprint> writes = WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 15,"// - + "\"address\": 5412,"// - + "\"value\": [" + String.join(",", MAX_COILS) + "]"// - + "}]"); - assertThat(writes.size(), is(equalTo(1))); - } - - @Test - public void testFC15MultipleCoilsTooManyCoils() { - assertThrows(IllegalArgumentException.class, () -> WriteRequestJsonUtilities.fromJson(55, "[{"// - + "\"functionCode\": 15,"// - + "\"address\": 5412,"// - + "\"value\": [" + String.join(",", OVER_MAX_COILS) + "]"// - + "}]")); - } - - @Test - public void testEmptyObject() { - // we are expecting list, not object -> error - assertThrows(IllegalStateException.class, () -> WriteRequestJsonUtilities.fromJson(3, "{}")); - } - - @Test - public void testNumber() { - // we are expecting list, not primitive (number) -> error - assertThrows(IllegalStateException.class, () -> WriteRequestJsonUtilities.fromJson(3, "3")); - } - - @Test - public void testEmptyList() { - assertThat(WriteRequestJsonUtilities.fromJson(3, "[]").size(), is(equalTo(0))); - } -} diff --git a/bundles/pom.xml b/bundles/pom.xml index f1dd83fb82102..714dcb5a91787 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -25,7 +25,6 @@ org.openhab.io.imperihome org.openhab.io.neeo org.openhab.io.openhabcloud - org.openhab.io.transport.modbus org.openhab.transform.bin2json org.openhab.transform.exec From 9aa24258f49495203b0c70499011396a3fde3c2f Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Mon, 7 Dec 2020 21:04:46 +0100 Subject: [PATCH 2/5] fixed all poms Signed-off-by: Kai Kreuzer --- bundles/org.openhab.binding.modbus.e3dc/pom.xml | 4 ++-- .../org.openhab.binding.modbus.helioseasycontrols/pom.xml | 6 +++--- bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml | 4 ++-- bundles/org.openhab.binding.modbus.studer/pom.xml | 4 ++-- bundles/org.openhab.binding.modbus.sunspec/pom.xml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.modbus.e3dc/pom.xml b/bundles/org.openhab.binding.modbus.e3dc/pom.xml index 6cf73d4e09035..7fc2e4f2a5e25 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/pom.xml +++ b/bundles/org.openhab.binding.modbus.e3dc/pom.xml @@ -22,8 +22,8 @@ provided - org.openhab.addons.bundles - org.openhab.io.transport.modbus + org.openhab.core.bundles + org.openhab.core.io.transport.modbus ${project.version} provided diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml index 82f20c63da48b..a6a34979fa46a 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml @@ -17,13 +17,13 @@ org.openhab.addons.bundles - org.openhab.io.transport.modbus + org.openhab.binding.modbus ${project.version} provided - org.openhab.addons.bundles - org.openhab.binding.modbus + org.openhab.core.bundles + org.openhab.core.io.transport.modbus ${project.version} provided diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml index fdd5566013ffe..d82e60f62f895 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml @@ -22,8 +22,8 @@ provided - org.openhab.addons.bundles - org.openhab.io.transport.modbus + org.openhab.core.bundles + org.openhab.core.io.transport.modbus ${project.version} provided diff --git a/bundles/org.openhab.binding.modbus.studer/pom.xml b/bundles/org.openhab.binding.modbus.studer/pom.xml index 603e22b2dabd3..32db23bb74029 100644 --- a/bundles/org.openhab.binding.modbus.studer/pom.xml +++ b/bundles/org.openhab.binding.modbus.studer/pom.xml @@ -21,8 +21,8 @@ provided - org.openhab.addons.bundles - org.openhab.io.transport.modbus + org.openhab.core.bundles + org.openhab.core.io.transport.modbus ${project.version} provided diff --git a/bundles/org.openhab.binding.modbus.sunspec/pom.xml b/bundles/org.openhab.binding.modbus.sunspec/pom.xml index 746b1cad26cd0..5b2de585d4c72 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/pom.xml +++ b/bundles/org.openhab.binding.modbus.sunspec/pom.xml @@ -22,8 +22,8 @@ provided - org.openhab.addons.bundles - org.openhab.io.transport.modbus + org.openhab.core.bundles + org.openhab.core.io.transport.modbus ${project.version} provided From 005fadcbfea475763815166ccb0be2ab368397ca Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Tue, 8 Dec 2020 19:45:09 +0100 Subject: [PATCH 3/5] some more fixes after rebase Signed-off-by: Kai Kreuzer --- bundles/org.openhab.binding.modbus.e3dc/pom.xml | 6 ------ .../org.openhab.binding.modbus.helioseasycontrols/pom.xml | 6 ------ bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml | 6 ------ .../stiebeleltron/internal/parser/AbstractBaseParser.java | 2 +- bundles/org.openhab.binding.modbus.studer/pom.xml | 6 ------ .../binding/modbus/studer/internal/StuderHandler.java | 2 +- bundles/org.openhab.binding.modbus.sunspec/pom.xml | 6 ------ .../sunspec/internal/discovery/SunspecDiscoveryProcess.java | 2 +- .../modbus/sunspec/internal/parser/AbstractBaseParser.java | 2 +- .../org.openhab.binding.modbus/src/main/feature/feature.xml | 2 +- .../modbus/internal/handler/ModbusDataThingHandler.java | 2 +- 11 files changed, 6 insertions(+), 36 deletions(-) diff --git a/bundles/org.openhab.binding.modbus.e3dc/pom.xml b/bundles/org.openhab.binding.modbus.e3dc/pom.xml index 7fc2e4f2a5e25..2f427e52d6b40 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/pom.xml +++ b/bundles/org.openhab.binding.modbus.e3dc/pom.xml @@ -21,11 +21,5 @@ ${project.version} provided - - org.openhab.core.bundles - org.openhab.core.io.transport.modbus - ${project.version} - provided - diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml index a6a34979fa46a..169c0f402484e 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml @@ -21,12 +21,6 @@ ${project.version} provided - - org.openhab.core.bundles - org.openhab.core.io.transport.modbus - ${project.version} - provided - diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml index d82e60f62f895..56f50a60cb8dc 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml @@ -21,12 +21,6 @@ ${project.version} provided - - org.openhab.core.bundles - org.openhab.core.io.transport.modbus - ${project.version} - provided - diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java index 6614c844cb0fa..1b8b0bc3b18de 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/java/org/openhab/binding/modbus/stiebeleltron/internal/parser/AbstractBaseParser.java @@ -16,8 +16,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.io.transport.modbus.ModbusBitUtilities; -import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.library.types.DecimalType; /** diff --git a/bundles/org.openhab.binding.modbus.studer/pom.xml b/bundles/org.openhab.binding.modbus.studer/pom.xml index 32db23bb74029..a4068d1b8838a 100644 --- a/bundles/org.openhab.binding.modbus.studer/pom.xml +++ b/bundles/org.openhab.binding.modbus.studer/pom.xml @@ -20,11 +20,5 @@ ${project.version} provided - - org.openhab.core.bundles - org.openhab.core.io.transport.modbus - ${project.version} - provided - diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java index 85765ff456505..08fa8f2aa8ef2 100644 --- a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java @@ -30,11 +30,11 @@ import org.openhab.core.io.transport.modbus.AsyncModbusFailure; import org.openhab.core.io.transport.modbus.ModbusBitUtilities; import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.io.transport.modbus.PollTask; -import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; diff --git a/bundles/org.openhab.binding.modbus.sunspec/pom.xml b/bundles/org.openhab.binding.modbus.sunspec/pom.xml index 5b2de585d4c72..3a1328159b6ca 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/pom.xml +++ b/bundles/org.openhab.binding.modbus.sunspec/pom.xml @@ -21,12 +21,6 @@ ${project.version} provided - - org.openhab.core.bundles - org.openhab.core.io.transport.modbus - ${project.version} - provided - diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java index 9f760887016db..4e64bcffa4104 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java @@ -33,10 +33,10 @@ import org.openhab.core.io.transport.modbus.AsyncModbusFailure; import org.openhab.core.io.transport.modbus.ModbusBitUtilities; import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; -import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.io.transport.modbus.exception.ModbusSlaveErrorResponseException; import org.openhab.core.library.types.DecimalType; import org.openhab.core.thing.ThingTypeUID; diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java index 47f6ef9877272..5afa91cfed19c 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/java/org/openhab/binding/modbus/sunspec/internal/parser/AbstractBaseParser.java @@ -16,8 +16,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.io.transport.modbus.ModbusBitUtilities; -import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.library.types.DecimalType; /** diff --git a/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml index de4b6572a86c1..f1fa59e89f569 100644 --- a/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml @@ -1,6 +1,6 @@ - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features openhab-runtime-base diff --git a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java index 0bd69bb776fd1..f7569b23e8d8e 100644 --- a/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java +++ b/bundles/org.openhab.binding.modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java @@ -38,13 +38,13 @@ import org.openhab.core.io.transport.modbus.ModbusBitUtilities; import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; import org.openhab.core.io.transport.modbus.ModbusConstants; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; import org.openhab.core.io.transport.modbus.ModbusRegisterArray; import org.openhab.core.io.transport.modbus.ModbusWriteCoilRequestBlueprint; import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; import org.openhab.core.io.transport.modbus.exception.ModbusConnectionException; import org.openhab.core.io.transport.modbus.exception.ModbusTransportException; import org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities; From bb2868bfafbad7c67b7732188f0d4c71d7e36aa5 Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Tue, 8 Dec 2020 20:22:52 +0100 Subject: [PATCH 4/5] adapted itests Signed-off-by: Kai Kreuzer --- .../itest.bndrun | 2 +- .../org.openhab.binding.modbus.tests/pom.xml | 5 --- .../modbus/tests/AbstractModbusOSGiTest.java | 4 +-- .../modbus/tests/ModbusDataHandlerTest.java | 34 +++++++++---------- .../tests/ModbusPollerThingHandlerTest.java | 24 ++++++------- .../tests/ModbusTcpThingHandlerTest.java | 6 ++-- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/itests/org.openhab.binding.modbus.tests/itest.bndrun b/itests/org.openhab.binding.modbus.tests/itest.bndrun index aa72c5904c54f..fad9dff0a489e 100644 --- a/itests/org.openhab.binding.modbus.tests/itest.bndrun +++ b/itests/org.openhab.binding.modbus.tests/itest.bndrun @@ -71,7 +71,7 @@ Fragment-Host: org.openhab.binding.modbus org.openhab.core.thing;version='[3.0.0,3.0.1)',\ org.openhab.core.thing.xml;version='[3.0.0,3.0.1)',\ org.openhab.core.transform;version='[3.0.0,3.0.1)',\ - org.openhab.io.transport.modbus;version='[3.0.0,3.0.1)',\ + org.openhab.core.io.transport.modbus;version='[3.0.0,3.0.1)',\ org.opentest4j;version='[1.2.0,1.2.1)',\ com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ diff --git a/itests/org.openhab.binding.modbus.tests/pom.xml b/itests/org.openhab.binding.modbus.tests/pom.xml index 19c4ad2f5a82f..84d8dd5f292e9 100644 --- a/itests/org.openhab.binding.modbus.tests/pom.xml +++ b/itests/org.openhab.binding.modbus.tests/pom.xml @@ -20,11 +20,6 @@ org.openhab.binding.modbus ${project.version} - - org.openhab.addons.bundles - org.openhab.io.transport.modbus - ${project.version} - diff --git a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/AbstractModbusOSGiTest.java b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/AbstractModbusOSGiTest.java index db09bced5b7e7..ae2274c618a96 100644 --- a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/AbstractModbusOSGiTest.java +++ b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/AbstractModbusOSGiTest.java @@ -42,6 +42,8 @@ import org.openhab.core.events.Event; import org.openhab.core.events.EventFilter; import org.openhab.core.events.EventSubscriber; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusManager; import org.openhab.core.items.Item; import org.openhab.core.items.ItemProvider; import org.openhab.core.items.ItemRegistry; @@ -60,8 +62,6 @@ import org.openhab.core.thing.link.ManagedItemChannelLinkProvider; import org.openhab.core.transform.TransformationService; import org.openhab.core.types.State; -import org.openhab.io.transport.modbus.ModbusCommunicationInterface; -import org.openhab.io.transport.modbus.ModbusManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusDataHandlerTest.java b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusDataHandlerTest.java index 65e99e86403ca..77fa7c3da1e07 100644 --- a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusDataHandlerTest.java +++ b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusDataHandlerTest.java @@ -36,6 +36,23 @@ import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler; import org.openhab.binding.modbus.internal.handler.ModbusTcpThingHandler; import org.openhab.core.config.core.Configuration; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.AsyncModbusWriteResult; +import org.openhab.core.io.transport.modbus.BitArray; +import org.openhab.core.io.transport.modbus.ModbusConstants; +import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.ModbusResponse; +import org.openhab.core.io.transport.modbus.ModbusWriteCoilRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint; +import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.openhab.core.items.GenericItem; import org.openhab.core.items.Item; import org.openhab.core.library.items.DateTimeItem; @@ -60,23 +77,6 @@ import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.AsyncModbusWriteResult; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusConstants; -import org.openhab.io.transport.modbus.ModbusConstants.ValueType; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.ModbusResponse; -import org.openhab.io.transport.modbus.ModbusWriteCoilRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteFunctionCode; -import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusWriteRequestBlueprint; -import org.openhab.io.transport.modbus.PollTask; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; diff --git a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusPollerThingHandlerTest.java b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusPollerThingHandlerTest.java index e527b0a9af635..26693da1093ef 100644 --- a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusPollerThingHandlerTest.java +++ b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusPollerThingHandlerTest.java @@ -35,6 +35,18 @@ import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal; import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler; import org.openhab.core.config.core.Configuration; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.BitArray; +import org.openhab.core.io.transport.modbus.ModbusConstants; +import org.openhab.core.io.transport.modbus.ModbusFailureCallback; +import org.openhab.core.io.transport.modbus.ModbusReadCallback; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint; +import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -43,18 +55,6 @@ import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.ThingHandlerCallback; import org.openhab.core.thing.binding.builder.BridgeBuilder; -import org.openhab.io.transport.modbus.AsyncModbusFailure; -import org.openhab.io.transport.modbus.AsyncModbusReadResult; -import org.openhab.io.transport.modbus.BitArray; -import org.openhab.io.transport.modbus.ModbusConstants; -import org.openhab.io.transport.modbus.ModbusFailureCallback; -import org.openhab.io.transport.modbus.ModbusReadCallback; -import org.openhab.io.transport.modbus.ModbusReadFunctionCode; -import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; -import org.openhab.io.transport.modbus.ModbusRegisterArray; -import org.openhab.io.transport.modbus.PollTask; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusTcpThingHandlerTest.java b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusTcpThingHandlerTest.java index 7f765e6072d95..5e18fe8e074ba 100644 --- a/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusTcpThingHandlerTest.java +++ b/itests/org.openhab.binding.modbus.tests/src/main/java/org/openhab/binding/modbus/tests/ModbusTcpThingHandlerTest.java @@ -25,14 +25,14 @@ import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal; import org.openhab.binding.modbus.internal.handler.ModbusTcpThingHandler; import org.openhab.core.config.core.Configuration; +import org.openhab.core.io.transport.modbus.endpoint.EndpointPoolConfiguration; +import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint; +import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.builder.BridgeBuilder; -import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration; -import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint; -import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; /** * @author Sami Salonen - Initial contribution From 3355af6c48cf5043d1f05345f3bc40430165ac30 Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Tue, 8 Dec 2020 22:39:26 +0100 Subject: [PATCH 5/5] removed unnecessary feature definitions Signed-off-by: Kai Kreuzer --- .../src/main/feature/feature.xml | 11 ----------- .../src/main/feature/feature.xml | 11 ----------- .../src/main/feature/feature.xml | 11 ----------- .../src/main/feature/feature.xml | 12 ------------ .../src/main/feature/feature.xml | 11 ----------- .../src/main/feature/feature.xml | 10 ---------- 6 files changed, 66 deletions(-) delete mode 100644 bundles/org.openhab.binding.modbus.e3dc/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.binding.modbus.sunspec/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.binding.modbus/src/main/feature/feature.xml diff --git a/bundles/org.openhab.binding.modbus.e3dc/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.e3dc/src/main/feature/feature.xml deleted file mode 100644 index 9cf00dffce341..0000000000000 --- a/bundles/org.openhab.binding.modbus.e3dc/src/main/feature/feature.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.e3dc/${project.version} - - diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/feature/feature.xml deleted file mode 100644 index 9988a5acf97e9..0000000000000 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/feature/feature.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.helioseasycontrols/${project.version} - - diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml deleted file mode 100644 index 5e1f17a38ce85..0000000000000 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/feature/feature.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.stiebeleltron/${project.version} - - diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml deleted file mode 100644 index 0d462e3553a53..0000000000000 --- a/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml - mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.studer/${project.version} - - diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.sunspec/src/main/feature/feature.xml deleted file mode 100644 index 5eb7e1afd7121..0000000000000 --- a/bundles/org.openhab.binding.modbus.sunspec/src/main/feature/feature.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.sunspec/${project.version} - - diff --git a/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml deleted file mode 100644 index f1fa59e89f569..0000000000000 --- a/bundles/org.openhab.binding.modbus/src/main/feature/feature.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features - - - openhab-runtime-base - openhab-transport-modbus - mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} - -