Modbus RTU getValue() parameters
-
I think I've managed to solve my problem.
I've tweaked ModbusLocator a bit, by changing bcdNibbleToInt():if (n > 9){ switch (n){ case 10: n = 0xA; break; case 11: n = 0xB; break; case 12: n = 0xC; break; case 13: n = 0xD; break; case 14: n = 0xE; break; case 15: n = 0xF; break; }
Now the result I get in Java as res:
Object res = master.getValue(locator);
is exactly the same as the one from Docklight.
-
Bytes higher than 0x9 in BCD are typically only defined as + or - indicators, not values. Perhaps the data you are receiving is not BCD?
-
You're probably right.
To be fair, I'm not really sure why this is working.
The thing is, any other DataType returns me numbers I cannot transform into useful data.
I know this because the slave is a meter which displays a measured value.
By using FOUR_BYTE_BCD I get the hex values corresponding to the numbers displayed.
Unfortunately, the meter's documentation isn't very explicit, and I couldn't find anything better online.
I'm going to test and investigate further. -
Can you post the full response message(s) and the value(s) that you are expecting?
-
Hello again, and sorry for the delayed response.
The value displayed on the meter is 1000 decimal ( = 3E8 hex). The response I get is:FOUR_BYTE_BCD: 8030000 EIGHT_BYTE_FLOAT: -1.0835797112716513E193 EIGHT_BYTE_FLOAT_SWAPPED: 1.03213875566E-310 EIGHT_BYTE_INT_SIGNED: -1728537831661371392 EIGHT_BYTE_INT_UNSIGNED: 16718206242048180224 FOUR_BYTE_FLOAT: -2.47452E24 TWO_BYTE_BCD: 803 TWO_BYTE_INT_UNSIGNED: 59395
The response structure is four bytes, as follows. (I know this from meter's documentation):
LowBit 1 | HighBit 1 | LowBit 2 | HighBit 2
Using FOUR_BYTE_BCD, I can expect:
E8 | 03 | 00 | 00
but every number > 9 is treated like 0, so E becomes 0 and disappears.
To overcome this, I've changed bcdNibbleToInt(...) like below:
private static String bcdNibbleToString(byte b, boolean high) { int n; if (high) n = (b >> 4) & 0xf; else n = b & 0xf; if (n > 9){ switch (n){ case 10: n = 0xA; break; case 11: n = 0xB; break; case 12: n = 0xC; break; case 13: n = 0xD; break; case 14: n = 0xE; break; case 15: n = 0xF; break; } if(n > 15) n = 0; } return String.format("%1X", n); }
and these lines in bytesToValue(...)
if (dataType == DataType.FOUR_BYTE_BCD) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 4; i++) { sb.append(bcdNibbleToString(data[offset + i], true)); sb.append(bcdNibbleToString(data[offset + i], false)); } return sb.toString(); }
This is for my particular case and it works.
I'm not exactly sure what kind of format to expect from the meter, but as long as this works, I guess I'll stick to it. -
What you need is what i would call a "four byte little endian int unsigned swapped". It's a mouthful.
All modbus4j data types are considered to be big endian, because that is the standard for Modbus. There's enough non-compliant Modbus hardware out there, but this deviation seems particularly egregious. Is there a setting or something that allows you to change the device's endianness?
-
The meter doesn't have that setting, as far as I know.
If it's not much of a wrongdoing, I think I'll use this modified version.
It is a bit strange, indeed. First time using modbus and comimg across something like this.
Thank you for helping me all along. -
Hi odious,
I wonder if you still active in this forum. I want to communicate my system with the device. And I following the example in the Modbus4J and it does not give me the result that I want. I was wondering, if you could give me the full code on how you create a connection between the device and the system and being able to read the data from the device. -
By the way odious, this is me writing a question in this forum. You can see what I've done so far, and maybe you can help me more. Thank you in advance for any kind of help and guidance.
Click here to read and understand more about my problem.
My Question