Skip to content

Commit 461ce8b

Browse files
committed
Do not wait for a reply for RTU broadcast address #61
1 parent ad58141 commit 461ce8b

File tree

3 files changed

+63
-39
lines changed

3 files changed

+63
-39
lines changed

src/conn.c

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,10 @@ conn_loop(void)
468468
#endif
469469
if (!tty.trynum) {
470470
modbus_ex_write(actconn->buf, MB_EX_CRC);
471+
#ifdef DEBUG
471472
logw(3, "tty: response is incorrect (%d of %d bytes, offset %d), return error", tty.ptrbuf,
472473
tty.rxoffset + tty.rxlen, tty.rxoffset);
474+
#endif
473475
} else
474476
{ /* retry request */
475477
#ifdef DEBUG
@@ -556,34 +558,46 @@ conn_loop(void)
556558
#ifdef DEBUG
557559
logw(7, "tty: request written (total %d bytes)", tty.txlen);
558560
#endif
559-
state_tty_set(&tty, TTY_RESP);
560-
switch (tty.txbuf[1]) {
561-
case 1:
562-
case 2:
563-
tty.rxlen = 5 + (tty.txbuf[4] * 256 + tty.txbuf[5] + 7)/8;
564-
break;
565-
case 3:
566-
case 4:
567-
tty.rxlen = 5 + tty.txbuf[5] * 2;
568-
break;
569-
case 7:
570-
tty.rxlen = 5;
571-
break;
572-
case 11:
573-
case 15:
574-
case 16:
575-
tty.rxlen = 8;
576-
break;
577-
default:
578-
tty.rxlen = tty.txlen;
579-
break;
561+
if (!tty.txbuf[0])
562+
{
563+
/* broadcast request sent, no reply expected */
564+
state_conn_set(actconn, CONN_HEADER);
565+
state_tty_set(&tty, TTY_PAUSE);
566+
#ifdef DEBUG
567+
logw(5, "conn[%s]: broadcast request sent", curconn->remote_addr);
568+
#endif
580569
}
581-
if (tty.rxlen > TTY_BUFSIZE)
582-
tty.rxlen = TTY_BUFSIZE;
583-
tty.timer += DV(tty.rxlen, tty.bpc, tty.speed);
570+
else
571+
{
572+
state_tty_set(&tty, TTY_RESP);
573+
switch (tty.txbuf[1]) {
574+
case 1:
575+
case 2:
576+
tty.rxlen = 5 + (tty.txbuf[4] * 256 + tty.txbuf[5] + 7)/8;
577+
break;
578+
case 3:
579+
case 4:
580+
tty.rxlen = 5 + tty.txbuf[5] * 2;
581+
break;
582+
case 7:
583+
tty.rxlen = 5;
584+
break;
585+
case 11:
586+
case 15:
587+
case 16:
588+
tty.rxlen = 8;
589+
break;
590+
default:
591+
tty.rxlen = tty.txlen;
592+
break;
593+
}
594+
if (tty.rxlen > TTY_BUFSIZE)
595+
tty.rxlen = TTY_BUFSIZE;
596+
tty.timer += DV(tty.rxlen, tty.bpc, tty.speed);
584597
#ifdef DEBUG
585-
logw(5, "tty: estimated %d bytes, waiting %lu usec", tty.rxlen, tty.timer);
598+
logw(5, "tty: estimated %d bytes, waiting %lu usec", tty.rxlen, tty.timer);
586599
#endif
600+
}
587601
}
588602
}
589603

tests/environment/rtu_slave.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def _start_rtu_server(self, framer=ModbusRtuFramer):
112112
#---------------------------------------------------------------------------#
113113
#StartTcpServer(context, identity=identity, address=("localhost", 5020))
114114
#StartUdpServer(context, identity=identity, address=("localhost", 502))
115-
StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer)
115+
StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer, broadcast_enable=True)
116116
#StartSerialServer(context, identity=identity, port='/dev/pts/3', framer=ModbusAsciiFramer)
117117

118118
p = None

tests/run_itests.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ def setUpClass(cls):
3333
cls.mbs.start()
3434

3535
cls.log.debug("3. run mbusd to be tested with the binary:%s" % MBUSD_BINARY)
36-
cls.mbusd_main = Popen([MBUSD_BINARY, "-d", "-L", "-v9", "-p/tmp/pts0", "-s19200", "-P" + str(MBUSD_PORT)],
36+
cls.mbusd_main = Popen([MBUSD_BINARY, "-d", "-L/tmp/mbusd.log", "-v9", "-p/tmp/pts0", "-s19200", "-P" + str(MBUSD_PORT)],
3737
stdout=PIPE, stderr=STDOUT)
3838
# wait a little bit for mbusd to come up
3939
# alternatively do a poll for the socket
4040
# https://stackoverflow.com/questions/667640/how-to-tell-if-a-connection-is-dead-in-python/667702#667702
4141
sleep(5)
4242

4343
cls.log.debug("4. connect the modbus TCP client to mbusd")
44-
cls.client = ModbusTcpClient('127.0.0.1', port=MBUSD_PORT)
44+
cls.client = ModbusTcpClient('127.0.0.1', port=MBUSD_PORT, broadcast_enable=True)
4545
cls.client.connect()
4646

4747
@classmethod
@@ -62,68 +62,78 @@ def test_coils(self):
6262
bits = [random.randrange(2)>0 for i in range(8)]
6363

6464
# 15 Write Multiple Coils
65-
result = self.client.write_coils(0, bits)
65+
result = self.client.write_coils(0, bits, unit=1)
6666
self.assertIsInstance(result, WriteMultipleCoilsResponse, result)
6767
self.assertEqual(result.address, 0, result)
6868
self.assertEqual(result.count, 8, result)
6969

7070
# 01 Read Coils
71-
result = self.client.read_coils(0, 8)
71+
result = self.client.read_coils(0, 8, unit=1)
7272
self.assertIsInstance(result, ReadCoilsResponse, result)
7373
self.assertEqual(result.bits, bits, result)
7474

7575
# 05 Write Single Coil
7676
bit1 = not bits[0]
77-
result = self.client.write_coil(0, bit1)
77+
result = self.client.write_coil(0, bit1, unit=1)
7878
self.assertIsInstance(result, WriteSingleCoilResponse, result)
7979
self.assertEqual(result.address, 0, result)
8080
self.assertEqual(result.value, bit1, result)
81-
result = self.client.read_coils(0, 1)
81+
result = self.client.read_coils(0, 1, unit=1)
8282
self.assertIsInstance(result, ReadCoilsResponse, result)
8383
self.assertEqual(result.bits[0], bit1, result)
8484

8585
def test_discreteInputs(self):
8686
# 02 Read Discrete Inputs
87-
result = self.client.read_discrete_inputs(0, 8)
87+
result = self.client.read_discrete_inputs(0, 8, unit=1)
8888
self.assertIsInstance(result, ReadDiscreteInputsResponse, result)
8989
self.assertEqual(result.bits, [True]*8, result)
9090

9191
def test_inputRegisters(self):
9292
# 04 Read Input Registers
93-
result = self.client.read_input_registers(0, 8)
93+
result = self.client.read_input_registers(0, 8, unit=1)
9494
self.assertIsInstance(result, ReadInputRegistersResponse, result)
9595
self.assertEqual(result.registers, list(range(8)), result)
9696

9797
def test_holdingRegisters(self):
9898
registers = [random.randrange(8) for i in range(8)]
9999

100100
# 16 Write Multiple Holding Registers
101-
result = self.client.write_registers(0, registers)
101+
result = self.client.write_registers(0, registers, unit=1)
102102
self.assertIsInstance(result, WriteMultipleRegistersResponse, result)
103103
self.assertEqual(result.address, 0, result)
104104
self.assertEqual(result.count, 8, result)
105105

106106
# 03 Read Multiple Holding Registers
107-
result = self.client.read_holding_registers(0, 8)
107+
result = self.client.read_holding_registers(0, 8, unit=1)
108108
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
109109
self.assertEqual(result.registers, registers, result)
110110

111111
# 06 Write Single Holding Register
112112
register1 = (registers[0] + 1) % 65535
113-
result = self.client.write_register(0, register1)
113+
result = self.client.write_register(0, register1, unit=1)
114114
self.assertIsInstance(result, WriteSingleRegisterResponse, result)
115115
self.assertEqual(result.address, 0, result)
116116
self.assertEqual(result.value, register1, result)
117-
result = self.client.read_holding_registers(0, 1)
117+
result = self.client.read_holding_registers(0, 1, unit=1)
118118
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
119119
self.assertEqual(result.registers[0], register1, result)
120120

121121
def test_exception(self):
122-
result = self.client.write_coil(1000, False) # invalid address 1000
122+
result = self.client.write_coil(1000, False, unit=1) # invalid address 1000
123123
self.assertIsInstance(result, ExceptionResponse, result)
124124
self.assertEqual(result.original_code, 5, result) # fc05 Write Single Coil
125125
self.assertEqual(result.exception_code, 2, result) # Illegal Data Address
126126

127+
def test_broadcast(self):
128+
registers = [random.randrange(8) for i in range(8)]
129+
# 16 Write Multiple Holding Registers
130+
result = self.client.write_registers(0, registers, unit=0)
131+
132+
# 03 Read Multiple Holding Registers
133+
result = self.client.read_holding_registers(0, 8, unit=1)
134+
self.assertIsInstance(result, ReadHoldingRegistersResponse, result)
135+
self.assertEqual(result.registers, registers, result)
136+
127137
if __name__ == '__main__':
128138
stdout_handler = logging.StreamHandler(sys.stdout)
129139
logging.basicConfig(level=logging.DEBUG,

0 commit comments

Comments
 (0)