python-3.xmodbus-tcpmodbus-tk

modbus-tk getting Modbus Error: Exception code = 2


I am using modbus-tk for simulate modbus device for unittest.

I am added 2 block data.

def add_test_1(self):
    point = "Test_1"
    addr = 40003
    self.slave_1.add_block(point, mbdefines.HOLDING_REGISTERS, addr, 1)
    self.slave_1.set_values(point, addr, 5)

def add_test_2(self):
    point = "Test_2"
    addr = 40004
    self.slave_1.add_block(point, mbdefines.HOLDING_REGISTERS, addr, 2)
    self.slave_1.set_values(point, addr, (16560, 0))

But when I use modbus-tk for reading multi register.

result = modbus_client.execute(1, mbdefines.READ_HOLDING_REGISTERS, 40003, 3)
print(result)

The exception is raised.

Modbus Error: Exception code = 2

Meanwhile, I still can read multi data in real Modbus device by using this

result = modbus_client.execute(1, mbdefines.READ_HOLDING_REGISTERS, 40003, 3)
print(result)

With data look like block data I show it before

I'm using python 3.7.3 64-bit


Solution

  • The problem is that you create two different blocks.

    def add_test_1(self):
        point = "Test_1"
        addr = 40003
        self.slave_1.add_block(point, mbdefines.HOLDING_REGISTERS, addr, 1)
        self.slave_1.set_values(point, addr, 5)
    
    def add_test_2(self):
        point = "Test_2"
        addr = 40004
        self.slave_1.add_block(point, mbdefines.HOLDING_REGISTERS, addr, 2)
        self.slave_1.set_values(point, addr, (16560, 0))
    

    Both block can be read, but with two different commands:

    result_test_1 = modbus_client.execute(1, mbdefines.READ_HOLDING_REGISTERS, 40003, 1)
    print(result_test_1 )
    # (5, )
    
    result_test_2 = modbus_client.execute(1, mbdefines.READ_HOLDING_REGISTERS, 40004, 2)
    print(result_test_2 )
    # (16560, 0, )
    

    You can also create a single block and read it:

    def add_test():
        point = "Test_1"
        addr = 40003
        slave_1.add_block(point, cst.HOLDING_REGISTERS, addr, 3)
        slave_1.set_values(point, addr, (5, 16560, 0))
    
    result_test = modbus_client.execute(1, mbdefines.READ_HOLDING_REGISTERS, 40003, 3)
    print(result_test)
    # (5, 16560, 0, )
    

    As you can see on github there is a function called _get_block_and_offset that is called by _read_registers. When you read from your slave the server call the function _read_holding_registers that return the result of _read_registers, but when it reach the call to _get_block_and_offset it raise ModbusError(defines.ILLEGAL_DATA_ADDRESS) because the conditions address >= block.starting_address and block.size >= offset + length are not satisfied, so the return block, offset is never reached.