Do not wait for a reply for RTU broadcast address #61

This commit is contained in:
Victor Antonovich 2020-08-13 17:39:30 +04:00
parent ad58141b87
commit 461ce8baa0
3 changed files with 64 additions and 40 deletions

View File

@ -468,8 +468,10 @@ conn_loop(void)
#endif
if (!tty.trynum) {
modbus_ex_write(actconn->buf, MB_EX_CRC);
#ifdef DEBUG
logw(3, "tty: response is incorrect (%d of %d bytes, offset %d), return error", tty.ptrbuf,
tty.rxoffset + tty.rxlen, tty.rxoffset);
#endif
} else
{ /* retry request */
#ifdef DEBUG
@ -556,34 +558,46 @@ conn_loop(void)
#ifdef DEBUG
logw(7, "tty: request written (total %d bytes)", tty.txlen);
#endif
state_tty_set(&tty, TTY_RESP);
switch (tty.txbuf[1]) {
case 1:
case 2:
tty.rxlen = 5 + (tty.txbuf[4] * 256 + tty.txbuf[5] + 7)/8;
break;
case 3:
case 4:
tty.rxlen = 5 + tty.txbuf[5] * 2;
break;
case 7:
tty.rxlen = 5;
break;
case 11:
case 15:
case 16:
tty.rxlen = 8;
break;
default:
tty.rxlen = tty.txlen;
break;
}
if (tty.rxlen > TTY_BUFSIZE)
tty.rxlen = TTY_BUFSIZE;
tty.timer += DV(tty.rxlen, tty.bpc, tty.speed);
if (!tty.txbuf[0])
{
/* broadcast request sent, no reply expected */
state_conn_set(actconn, CONN_HEADER);
state_tty_set(&tty, TTY_PAUSE);
#ifdef DEBUG
logw(5, "tty: estimated %d bytes, waiting %lu usec", tty.rxlen, tty.timer);
logw(5, "conn[%s]: broadcast request sent", curconn->remote_addr);
#endif
}
else
{
state_tty_set(&tty, TTY_RESP);
switch (tty.txbuf[1]) {
case 1:
case 2:
tty.rxlen = 5 + (tty.txbuf[4] * 256 + tty.txbuf[5] + 7)/8;
break;
case 3:
case 4:
tty.rxlen = 5 + tty.txbuf[5] * 2;
break;
case 7:
tty.rxlen = 5;
break;
case 11:
case 15:
case 16:
tty.rxlen = 8;
break;
default:
tty.rxlen = tty.txlen;
break;
}
if (tty.rxlen > TTY_BUFSIZE)
tty.rxlen = TTY_BUFSIZE;
tty.timer += DV(tty.rxlen, tty.bpc, tty.speed);
#ifdef DEBUG
logw(5, "tty: estimated %d bytes, waiting %lu usec", tty.rxlen, tty.timer);
#endif
}
}
}

View File

@ -112,7 +112,7 @@ class ModbusSerialServer:
#---------------------------------------------------------------------------#
#StartTcpServer(context, identity=identity, address=("localhost", 5020))
#StartUdpServer(context, identity=identity, address=("localhost", 502))
StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer)
StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer, broadcast_enable=True)
#StartSerialServer(context, identity=identity, port='/dev/pts/3', framer=ModbusAsciiFramer)
p = None

View File

@ -33,7 +33,7 @@ class TestModbusRequests(unittest.TestCase):
cls.mbs.start()
cls.log.debug("3. run mbusd to be tested with the binary:%s" % MBUSD_BINARY)
cls.mbusd_main = Popen([MBUSD_BINARY, "-d", "-L", "-v9", "-p/tmp/pts0", "-s19200", "-P" + str(MBUSD_PORT)],
cls.mbusd_main = Popen([MBUSD_BINARY, "-d", "-L/tmp/mbusd.log", "-v9", "-p/tmp/pts0", "-s19200", "-P" + str(MBUSD_PORT)],
stdout=PIPE, stderr=STDOUT)
# wait a little bit for mbusd to come up
# alternatively do a poll for the socket
@ -41,7 +41,7 @@ class TestModbusRequests(unittest.TestCase):
sleep(5)
cls.log.debug("4. connect the modbus TCP client to mbusd")
cls.client = ModbusTcpClient('127.0.0.1', port=MBUSD_PORT)
cls.client = ModbusTcpClient('127.0.0.1', port=MBUSD_PORT, broadcast_enable=True)
cls.client.connect()
@classmethod
@ -62,35 +62,35 @@ class TestModbusRequests(unittest.TestCase):
bits = [random.randrange(2)>0 for i in range(8)]
# 15 Write Multiple Coils
result = self.client.write_coils(0, bits)
result = self.client.write_coils(0, bits, unit=1)
self.assertIsInstance(result, WriteMultipleCoilsResponse, result)
self.assertEqual(result.address, 0, result)
self.assertEqual(result.count, 8, result)
# 01 Read Coils
result = self.client.read_coils(0, 8)
result = self.client.read_coils(0, 8, unit=1)
self.assertIsInstance(result, ReadCoilsResponse, result)
self.assertEqual(result.bits, bits, result)
# 05 Write Single Coil
bit1 = not bits[0]
result = self.client.write_coil(0, bit1)
result = self.client.write_coil(0, bit1, unit=1)
self.assertIsInstance(result, WriteSingleCoilResponse, result)
self.assertEqual(result.address, 0, result)
self.assertEqual(result.value, bit1, result)
result = self.client.read_coils(0, 1)
result = self.client.read_coils(0, 1, unit=1)
self.assertIsInstance(result, ReadCoilsResponse, result)
self.assertEqual(result.bits[0], bit1, result)
def test_discreteInputs(self):
# 02 Read Discrete Inputs
result = self.client.read_discrete_inputs(0, 8)
result = self.client.read_discrete_inputs(0, 8, unit=1)
self.assertIsInstance(result, ReadDiscreteInputsResponse, result)
self.assertEqual(result.bits, [True]*8, result)
def test_inputRegisters(self):
# 04 Read Input Registers
result = self.client.read_input_registers(0, 8)
result = self.client.read_input_registers(0, 8, unit=1)
self.assertIsInstance(result, ReadInputRegistersResponse, result)
self.assertEqual(result.registers, list(range(8)), result)
@ -98,32 +98,42 @@ class TestModbusRequests(unittest.TestCase):
registers = [random.randrange(8) for i in range(8)]
# 16 Write Multiple Holding Registers
result = self.client.write_registers(0, registers)
result = self.client.write_registers(0, registers, unit=1)
self.assertIsInstance(result, WriteMultipleRegistersResponse, result)
self.assertEqual(result.address, 0, result)
self.assertEqual(result.count, 8, result)
# 03 Read Multiple Holding Registers
result = self.client.read_holding_registers(0, 8)
result = self.client.read_holding_registers(0, 8, unit=1)
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
self.assertEqual(result.registers, registers, result)
# 06 Write Single Holding Register
register1 = (registers[0] + 1) % 65535
result = self.client.write_register(0, register1)
result = self.client.write_register(0, register1, unit=1)
self.assertIsInstance(result, WriteSingleRegisterResponse, result)
self.assertEqual(result.address, 0, result)
self.assertEqual(result.value, register1, result)
result = self.client.read_holding_registers(0, 1)
result = self.client.read_holding_registers(0, 1, unit=1)
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
self.assertEqual(result.registers[0], register1, result)
def test_exception(self):
result = self.client.write_coil(1000, False) # invalid address 1000
result = self.client.write_coil(1000, False, unit=1) # invalid address 1000
self.assertIsInstance(result, ExceptionResponse, result)
self.assertEqual(result.original_code, 5, result) # fc05 Write Single Coil
self.assertEqual(result.exception_code, 2, result) # Illegal Data Address
def test_broadcast(self):
registers = [random.randrange(8) for i in range(8)]
# 16 Write Multiple Holding Registers
result = self.client.write_registers(0, registers, unit=0)
# 03 Read Multiple Holding Registers
result = self.client.read_holding_registers(0, 8, unit=1)
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
self.assertEqual(result.registers, registers, result)
if __name__ == '__main__':
stdout_handler = logging.StreamHandler(sys.stdout)
logging.basicConfig(level=logging.DEBUG,