Skip to content

Commit 77bdadd

Browse files
committed
TestModbusProtocol test_client_server_count passes
Regression to pass also write a coil to False
1 parent 3aa50a8 commit 77bdadd

File tree

4 files changed

+111
-19
lines changed

4 files changed

+111
-19
lines changed

minicps/devices.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,12 @@ def get(self, what):
227227
else:
228228
return self._state._get(what)
229229

230-
def send(self, what, value, address):
230+
def send(self, what, value, address, **kwargs):
231231
"""Send (write) a value to another network host.
232232
233+
``kwargs`` dict is used to pass extra key-value pair according to the
234+
used protocol.
235+
233236
:param tuple what: field[s] identifier[s]
234237
:param value: value to be setted
235238
:param str address: ``ip[:port]``
@@ -245,6 +248,9 @@ def send(self, what, value, address):
245248
def recieve(self, what, address, **kwargs):
246249
"""Receive (read) a value from another network host.
247250
251+
``kwargs`` dict is used to pass extra key-value pair according to the
252+
used protocol.
253+
248254
:param tuple what: field[s] identifier[s]
249255
:param str address: ``ip[:port]``
250256

minicps/protocols.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def _stop_server(cls, address):
8686

8787
print '_stop_server: please override me.'
8888

89-
def _send(self, what, value, address):
89+
def _send(self, what, value, address, **kwargs):
9090
"""Send (write) a value to another host.
9191
9292
:what: to send
@@ -349,7 +349,7 @@ def _stop_server(cls, server):
349349
except Exception as error:
350350
print 'ERROR stop enip server: ', error
351351

352-
def _send(self, what, value, address='localhost:44818'):
352+
def _send(self, what, value, address='localhost:44818', **kwargs):
353353
"""Send (write) a value to another host.
354354
355355
It is a blocking operation the parent process will wait till the child
@@ -607,14 +607,20 @@ def _stop_server(cls, server):
607607
print 'ERROR stop modbus server: ', error
608608

609609

610-
def _send(self, what, value, address='localhost:502'):
610+
def _send(self, what, value, address='localhost:502', **kwargs):
611611
"""Send (write) a value to another host.
612612
613613
It is a blocking operation the parent process will wait till the child
614614
cpppo process returns.
615615
616+
Boolean values are converted back and forth to integers because
617+
``argparse`` does not handle bool arguments correctly, eg: False
618+
string is evaluated and passed as True.
619+
616620
pymodbus has a ``count`` kwarg to perform sequential read and write
617-
starting from the offset passed inside ``what``.
621+
starting from the offset passed inside ``what``. Default call will
622+
write one value at a time. Pass a list of values if ``count`` is
623+
greater than one.
618624
619625
620626
:what: tuple addressing what
@@ -629,10 +635,40 @@ def _send(self, what, value, address='localhost:502'):
629635
MODE = '-m {} '.format('w')
630636
TYPE = '-t {} '.format(what[0])
631637
OFFSET = '-o {} '.format(what[1]) # NOTE: 0-based
638+
639+
# NOTE: value is a list of bools or ints when write multiple times
640+
if 'count' in kwargs and kwargs['count'] > 1:
641+
count = kwargs['count']
642+
COUNT = '--count {} '.format(count)
643+
else:
644+
count = 1
645+
COUNT = '--count {} '.format(count)
646+
647+
# NOTE: value is a int when writing to a register
632648
if what[0] == 'HR':
633-
VALUE = '-r {} '.format(value)
649+
if count == 1:
650+
VALUE = '-r {} '.format(value)
651+
else:
652+
VALUE = '-r '
653+
for v in value:
654+
VALUE += str(v)
655+
VALUE += ' '
656+
657+
# NOTE: value is a bool when writing to a coil
634658
elif what[0] == 'CO':
635-
VALUE = '-c {} '.format(value)
659+
if count == 1:
660+
if value == True:
661+
VALUE = '-c {} '.format(1)
662+
else:
663+
VALUE = '-c {} '.format(0)
664+
else:
665+
VALUE = '-c '
666+
for v in value:
667+
if v == True:
668+
VALUE += str(1)
669+
else:
670+
VALUE += str(0)
671+
VALUE += ' '
636672
else:
637673
raise ValueError('IR and DI are read only data.')
638674

@@ -644,6 +680,7 @@ def _send(self, what, value, address='localhost:502'):
644680
MODE +
645681
TYPE +
646682
OFFSET +
683+
COUNT +
647684
VALUE
648685
)
649686
# print 'DEBUG modbus_send cmd shlex list: ', cmd
@@ -664,7 +701,7 @@ def _receive(self, what, address='localhost:502', **kwargs):
664701
cpppo process returns.
665702
666703
pymodbus has a ``count`` kwarg to perform sequential read and write
667-
starting from the offset passed inside ``what``. Default setup will
704+
starting from the offset passed inside ``what``. Default call will
668705
request and return one value at a time.
669706
670707
The return type depends on the request type:

scripts/pymodbus/synch-client.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@
4040
type=int, choices=range(1,2000), # NOTE: bounds from the standard
4141
default=1)
4242
parser.add_argument('-r', dest='register',
43-
help='register value', type=int, choices=range(0, 65536),
43+
help='list of int values', type=int,
44+
choices=range(0, 65536), nargs='+',
4445
default=0)
4546
parser.add_argument('-c', dest='coil',
46-
help='coil value', type=bool,
47-
default=True) # NOTE: implicit True False choice
47+
help='list of 0 (False) or 1 (True) int values', type=int, nargs='+',
48+
default=0, choices=[0, 1]) # argparse does not manage bool well
4849

4950
args = parser.parse_args()
5051

@@ -65,16 +66,31 @@
6566
# NOTE: write_register
6667
if args.type == 'HR':
6768
if args.count == 1:
68-
hr_write = client.write_register(args.offset, int(args.register))
69+
hr_write = client.write_register(args.offset, args.register[0])
6970
assert(hr_write.function_code < 0x80)
70-
# TODO: implement
71-
# else:
72-
# hrs_write = client.write_registers(args.offset, args.values)
71+
else:
72+
hrs_write = client.write_registers(args.offset, args.register)
73+
assert(hrs_write.function_code < 0x80)
7374

74-
# NOTE: write_coil
75+
# NOTE: write_coil: map integers to bools
7576
elif args.type == 'CO':
76-
co_write = client.write_coil(args.offset, args.coil)
77-
assert(co_write.function_code < 0x80)
77+
78+
if args.count == 1:
79+
if args.coil == 1:
80+
co_write = client.write_coil(args.offset, True)
81+
else:
82+
co_write = client.write_coil(args.offset, False)
83+
assert(co_write.function_code < 0x80)
84+
85+
else:
86+
coils = []
87+
for c in args.coil:
88+
if c == 1:
89+
coils.append(True)
90+
else:
91+
coils.append(False)
92+
cos_write = client.write_coils(args.offset, coils)
93+
assert(cos_write.function_code < 0x80)
7894

7995

8096
elif args.mode == 'r':

tests/protocols_tests.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ def test_receive(self):
347347
print 'ERROR test_receive: ', error
348348
assert False
349349

350+
@SkipTest
350351
def test_client_server(self):
351352

352353
ADDRESS = 'localhost:502'
@@ -363,6 +364,12 @@ def test_client_server(self):
363364
modbus._send(what, value, ADDRESS)
364365
what = ('CO', 0)
365366
eq_(modbus._receive(what, ADDRESS), True)
367+
368+
what = ('CO', 1)
369+
value = False
370+
modbus._send(what, value, ADDRESS)
371+
what = ('CO', 1)
372+
eq_(modbus._receive(what, ADDRESS), False)
366373
print('')
367374

368375
print('TEST: Write and read holding registers')
@@ -398,7 +405,6 @@ def test_receive_count(self):
398405

399406
ADDRESS = 'localhost:502'
400407
TAGS = (20, 20, 20, 20)
401-
OFFSET = 10
402408

403409
try:
404410
server = ModbusProtocol._start_server(ADDRESS, TAGS)
@@ -430,4 +436,31 @@ def test_receive_count(self):
430436
ModbusProtocol._stop_server(server)
431437
print 'ERROR test_receive_count: ', error
432438
assert False
439+
440+
def test_client_server_count(self):
441+
442+
client = ModbusProtocol(
443+
protocol=TestModbusProtocol.CLIENT_PROTOCOL)
444+
445+
ADDRESS = 'localhost:502'
446+
TAGS = (50, 50, 50, 50)
447+
448+
try:
449+
server = ModbusProtocol._start_server(ADDRESS, TAGS)
450+
time.sleep(1.0)
451+
452+
print('TEST: Write and Read holding registers, offset=4, count=3')
453+
what = ('HR', 4)
454+
values = [1, 2, 3]
455+
client._send(what, values, ADDRESS, count=3)
456+
eq_(client._receive(what, ADDRESS, count=3), [1, 2, 3])
457+
print('')
458+
459+
460+
ModbusProtocol._stop_server(server)
461+
462+
except Exception as error:
463+
ModbusProtocol._stop_server(server)
464+
print 'ERROR test_client_server_count: ', error
465+
assert False
433466
# }}}

0 commit comments

Comments
 (0)