We have a service interface for Modbus devices that we can use remotely from Java. Modbus supports only very basic data types like single bits and 16-bit words. Our service interface provides the contents of a 16-bit input or holding register as a Java integer.
Often one 16-bit register is not enough to solve a problem in your domain, like representing a temperature as floating point number. A common solution is to combine two 16-bit registers and interpret their contents as a floating point number.
So the question is how to combine the bits of the two int values and convert them to a float in Java. There are at least two possiblities I want to show you.
The “old-fashioned” way includes bit-shifting and bit-wise operators which you actually can use in Java despite of the major flaw regarding primitive types: there are no unsigned data types; even byte is signed!
public static float floatFrom(int mostSignificat16Bits, int leastSignificant16Bits) { int bits = (mostSignificat16Bits << 16) | leastSignificant16Bits; return Float.intBitsToFloat(bits); }
As seemingly more modern way is using java.nio.ByteBuffer
:
public static float nioFloatFrom(int mostSignificat16Bits, int leastSignificant16Bits) { final ByteBuffer buf = ByteBuffer.allocate(4).putShort((short) mostSignificat16Bits).putShort((short) leastSignificant16Bits); buf.rewind(); // rewind to the beginning of the buffer, so it can be read! return buf.getFloat(); }
The second method seems superior when working with many values because you can fill the buffer conveniently in one phase and extract the float values conveniently by subsequent calls to getFloat()
.
Conclusion
Even if it is not one of Java’s strengths you actually can work on the bit- and byte-level and perform low level tasks. Do not let the lack of unsigned data types scare you; signedness is irrelevant for the bits in memory.