Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

  • Hello,
    I want to use modbus4j to communicate with a slave device via serial.
    The correct hex interogation is: 01 03 00 01 00 01 D5 CA - I tested this in another program(Docklight) and I got the desired response.
    How would I go about translating this as parameters for getValue()?
    What I've done was to create a ModbusFactory instance, set the serial params and create a ModbusMaster.
    Now I need to do something like master.getValue(...);
    I've read the documentation, but I'm not entirely sure what's the correct approach for this method's parameters.
    I need a bit of help.
    Thank you.


  • You pass a Locator object to the getValue method. I believe the correct locator creation code for your case is:

    BaseLocator.holdingRegister(1, 0, DataType.TWO_BYTE_INT_UNSIGNED)
    

    ... although i'm not sure that data type you need to have returned.


  • Thanks a lot, it really helped me. It turns out what I needed was this:

    ModbusLocator locator = new ModbusLocator(1, RegisterRange.HOLDING_REGISTER, 1, DataType.FOUR_BYTE_BCD);
    

  • I have another little problem right now:
    Let's say my meter counter has the value 1000 displayed.
    The correct response is "E8 03 00 00", which I get in Docklight.
    (E8 is low-bit, so I actually get 03 E8, which is 1000 in decimal - correct)
    Interestingly enough, the response I get in Java is "8 03 00 00" - the E disappears.
    Is there any way to solve this ? The Locator is the one from above.
    Thanks again.


  • No idea. How do you know that those bytes are what is being received in Java? Did you turn on I/O logging?


  • 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