diff --git a/dc3-driver/dc3-driver-fins/src/main/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImpl.java b/dc3-driver/dc3-driver-fins/src/main/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImpl.java index f915e463a..678ef0c14 100644 --- a/dc3-driver/dc3-driver-fins/src/main/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImpl.java +++ b/dc3-driver/dc3-driver-fins/src/main/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImpl.java @@ -164,7 +164,7 @@ public class FinsDriverCustomServiceImpl implements DriverCustomService { try { byte areaCode = resolveMemoryAreaCode(memoryArea); - byte[] finsFrame = buildMemoryReadFrame(driverConfig, areaCode, address, 1); + byte[] finsFrame = buildMemoryReadFrame(driverConfig, areaCode, address, wordCount(dataType)); byte[] response = sendFinsCommand(socket, finsFrame); String value = parseReadResponse(response, dataType); @@ -402,7 +402,7 @@ public class FinsDriverCustomServiceImpl implements DriverCustomService { * @param dataType data type identifier * @return decoded value string */ - private String decodeValue(byte[] data, String dataType) { + String decodeValue(byte[] data, String dataType) { return switch (dataType.toUpperCase()) { case "INT16" -> String.valueOf(ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN).getShort()); case "UINT16" -> @@ -417,6 +417,20 @@ public class FinsDriverCustomServiceImpl implements DriverCustomService { }; } + /** + * Resolve the FINS memory read length in words (2 bytes each) for a data type. + * 32-bit types (INT32/UINT32/FLOAT) span 2 words; all others read a single word. + * + * @param dataType data type identifier + * @return word count to request + */ + int wordCount(String dataType) { + return switch (dataType.toUpperCase()) { + case "INT32", "UINT32", "FLOAT" -> 2; + default -> 1; + }; + } + /** * Encode a string value to bytes for FINS write operations. * @@ -424,7 +438,7 @@ public class FinsDriverCustomServiceImpl implements DriverCustomService { * @param dataType data type identifier * @return encoded bytes */ - private byte[] encodeWriteData(String value, String dataType) { + byte[] encodeWriteData(String value, String dataType) { byte[] data; switch (dataType.toUpperCase()) { case "INT16": @@ -435,13 +449,18 @@ public class FinsDriverCustomServiceImpl implements DriverCustomService { break; } case "INT32": - case "UINT32": - case "FLOAT": { + case "UINT32": { data = new byte[4]; int i = Integer.parseInt(value); ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN).putInt(i); break; } + case "FLOAT": { + data = new byte[4]; + float f = Float.parseFloat(value); + ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN).putFloat(f); + break; + } case "STRING": { data = value.getBytes(); break; diff --git a/dc3-driver/dc3-driver-fins/src/test/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImplTest.java b/dc3-driver/dc3-driver-fins/src/test/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImplTest.java index 5cf4fcc59..b427a9b79 100644 --- a/dc3-driver/dc3-driver-fins/src/test/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImplTest.java +++ b/dc3-driver/dc3-driver-fins/src/test/java/io/github/pnoker/driver/service/impl/FinsDriverCustomServiceImplTest.java @@ -91,4 +91,31 @@ class FinsDriverCustomServiceImplTest { assertThatNoException().isThrownBy(() -> service.schedule()); } + @Test + void wordCountIsTwoFor32BitTypesAndOneOtherwise() { + assertThat(service.wordCount("INT32")).isEqualTo(2); + assertThat(service.wordCount("UINT32")).isEqualTo(2); + assertThat(service.wordCount("FLOAT")).isEqualTo(2); + assertThat(service.wordCount("float")).isEqualTo(2); + assertThat(service.wordCount("INT16")).isEqualTo(1); + assertThat(service.wordCount("UINT16")).isEqualTo(1); + assertThat(service.wordCount("STRING")).isEqualTo(1); + } + + @Test + void floatEncodeDecodeRoundTrips() { + byte[] encoded = service.encodeWriteData("3.14", "FLOAT"); + + assertThat(encoded).hasSize(4); + assertThat(Float.parseFloat(service.decodeValue(encoded, "FLOAT"))).isEqualTo(3.14f); + } + + @Test + void int32EncodeDecodeRoundTrips() { + byte[] encoded = service.encodeWriteData("70000", "INT32"); + + assertThat(encoded).hasSize(4); + assertThat(service.decodeValue(encoded, "INT32")).isEqualTo("70000"); + } + }