Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ install:
@test -d "$(VIRTUAL_ENV)" || mkdir -p "$(VIRTUAL_ENV)"
@test -x "$(VIRTUAL_ENV)/bin/python" || virtualenv --quiet "$(VIRTUAL_ENV)"
@test -x "$(VIRTUAL_ENV)/bin/pip" || easy_install pip
@pip install --quiet --requirement=requirements.txt
@pip install --upgrade --quiet --requirement=requirements.txt
@pip uninstall --yes pymodbus &>/dev/null || true
@pip install --quiet --no-deps --ignore-installed .

Expand All @@ -38,15 +38,15 @@ check: install
@flake8

test: install
@pip install --quiet --requirement=requirements-tests.txt
@pip install --upgrade --quiet --requirement=requirements-tests.txt
@pytest --cov=pymodbus/ --cov-report term-missing
@coverage report --fail-under=90

tox: install
@pip install --quiet tox && tox
@pip install --upgrade --quiet tox && tox

docs: install
@pip install --quiet --requirement=requirements-docs.txt
@pip install --upgrade --quiet --requirement=requirements-docs.txt
@cd doc && make clean && make html

publish: install
Expand Down
8 changes: 4 additions & 4 deletions examples/common/async_asyncio_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
# Import the required asynchronous client
# ----------------------------------------------------------------------- #
from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient as ModbusClient
from pymodbus.client.asynchronous.udp import (
AsyncModbusUDPClient as ModbusClient)
# from pymodbus.client.asynchronous.udp import (
# AsyncModbusUDPClient as ModbusClient)
from pymodbus.client.asynchronous import schedulers

else:
Expand Down Expand Up @@ -207,9 +207,9 @@ def run_with_no_loop():
run_with_no_loop()

# Run with loop not yet started
run_with_not_running_loop()
# run_with_not_running_loop()

# Run with already running loop
run_with_already_running_loop()
# run_with_already_running_loop()

log.debug("")
2 changes: 1 addition & 1 deletion examples/common/custom_datablock.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def setValues(self, address, value):
:param address: The starting address
:param values: The new values to be set
"""
super(ModbusSparseDataBlock, self).setValues(address, value)
super(CustomDataBlock, self).setValues(address, value)

# whatever you want to do with the written value is done here,
# however make sure not to do too much work here or it will
Expand Down
194 changes: 103 additions & 91 deletions examples/common/modbus_payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
log = logging.getLogger()
log.setLevel(logging.INFO)

ORDER_DICT = {
"<": "LITTLE",
">": "BIG"
}


def run_binary_payload_ex():
# ----------------------------------------------------------------------- #
Expand Down Expand Up @@ -71,97 +76,104 @@ def run_binary_payload_ex():
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #

# ----------------------------------------------------------------------- #
builder = BinaryPayloadBuilder(byteorder=Endian.Big,
wordorder=Endian.Little)
builder.add_string('abcdefgh')
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
builder.add_8bit_int(-0x12)
builder.add_8bit_uint(0x12)
builder.add_16bit_int(-0x5678)
builder.add_16bit_uint(0x1234)
builder.add_32bit_int(-0x1234)
builder.add_32bit_uint(0x12345678)
builder.add_16bit_float(12.34)
builder.add_16bit_float(-12.34)
builder.add_32bit_float(22.34)
builder.add_32bit_float(-22.34)
builder.add_64bit_int(-0xDEADBEEF)
builder.add_64bit_uint(0x12345678DEADBEEF)
builder.add_64bit_uint(0x12345678DEADBEEF)
builder.add_64bit_float(123.45)
builder.add_64bit_float(-123.45)
payload = builder.to_registers()
print("-" * 60)
print("Writing Registers")
print("-" * 60)
print(payload)
print("\n")
payload = builder.build()
address = 0
# Can write registers
# registers = builder.to_registers()
# client.write_registers(address, registers, unit=1)

# Or can write encoded binary string
client.write_registers(address, payload, skip_encode=True, unit=1)
# ----------------------------------------------------------------------- #
# If you need to decode a collection of registers in a weird layout, the
# payload decoder can help you as well.
#
# Here we demonstrate decoding a random register layout, unpacked it looks
# like the following:
#
# - a 8 byte string 'abcdefgh'
# - a 32 bit float 22.34
# - a 16 bit unsigned int 0x1234
# - another 16 bit unsigned int which we will ignore
# - an 8 bit int 0x12
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
# ----------------------------------------------------------------------- #
address = 0x0
count = len(payload)
result = client.read_holding_registers(address, count, unit=1)
print("-" * 60)
print("Registers")
print("-" * 60)
print(result.registers)
print("\n")
decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
byteorder=Endian.Big,
wordorder=Endian.Little)

assert decoder._byteorder == builder._byteorder, \
"Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"

assert decoder._wordorder == builder._wordorder, \
"Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"


decoded = OrderedDict([
('string', decoder.decode_string(8)),
('bits', decoder.decode_bits()),
('8int', decoder.decode_8bit_int()),
('8uint', decoder.decode_8bit_uint()),
('16int', decoder.decode_16bit_int()),
('16uint', decoder.decode_16bit_uint()),
('32int', decoder.decode_32bit_int()),
('32uint', decoder.decode_32bit_uint()),
('16float', decoder.decode_16bit_float()),
('16float2', decoder.decode_16bit_float()),
('32float', decoder.decode_32bit_float()),
('32float2', decoder.decode_32bit_float()),
('64int', decoder.decode_64bit_int()),
('64uint', decoder.decode_64bit_uint()),
('ignore', decoder.skip_bytes(8)),
('64float', decoder.decode_64bit_float()),
('64float2', decoder.decode_64bit_float()),
])

print("-" * 60)
print("Decoded Data")
print("-" * 60)
for name, value in iteritems(decoded):
print("%s\t" % name, hex(value) if isinstance(value, int) else value)
combos = [(wo, bo) for wo in [Endian.Big, Endian.Little] for bo in [Endian.Big, Endian.Little]]
for wo, bo in combos:
print("-" * 60)
print("Word Order: {}".format(ORDER_DICT[wo]))
print("Byte Order: {}".format(ORDER_DICT[bo]))
print()
builder = BinaryPayloadBuilder(byteorder=bo,
wordorder=wo)
strng = "abcdefgh"
builder.add_string(strng)
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
builder.add_8bit_int(-0x12)
builder.add_8bit_uint(0x12)
builder.add_16bit_int(-0x5678)
builder.add_16bit_uint(0x1234)
builder.add_32bit_int(-0x1234)
builder.add_32bit_uint(0x12345678)
builder.add_16bit_float(12.34)
builder.add_16bit_float(-12.34)
builder.add_32bit_float(22.34)
builder.add_32bit_float(-22.34)
builder.add_64bit_int(-0xDEADBEEF)
builder.add_64bit_uint(0x12345678DEADBEEF)
builder.add_64bit_uint(0x12345678DEADBEEF)
builder.add_64bit_float(123.45)
builder.add_64bit_float(-123.45)
payload = builder.to_registers()
print("-" * 60)
print("Writing Registers")
print("-" * 60)
print(payload)
print("\n")
payload = builder.build()
address = 0
# Can write registers
# registers = builder.to_registers()
# client.write_registers(address, registers, unit=1)

# Or can write encoded binary string
client.write_registers(address, payload, skip_encode=True, unit=1)
# ----------------------------------------------------------------------- #
# If you need to decode a collection of registers in a weird layout, the
# payload decoder can help you as well.
#
# Here we demonstrate decoding a random register layout, unpacked it looks
# like the following:
#
# - a 8 byte string 'abcdefgh'
# - a 32 bit float 22.34
# - a 16 bit unsigned int 0x1234
# - another 16 bit unsigned int which we will ignore
# - an 8 bit int 0x12
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
# ----------------------------------------------------------------------- #
address = 0x0
count = len(payload)
result = client.read_holding_registers(address, count, unit=1)
print("-" * 60)
print("Registers")
print("-" * 60)
print(result.registers)
print("\n")
decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
byteorder=bo,
wordorder=wo)

assert decoder._byteorder == builder._byteorder, \
"Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"

assert decoder._wordorder == builder._wordorder, \
"Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"


decoded = OrderedDict([
('string', decoder.decode_string(len(strng))),
('bits', decoder.decode_bits()),
('8int', decoder.decode_8bit_int()),
('8uint', decoder.decode_8bit_uint()),
('16int', decoder.decode_16bit_int()),
('16uint', decoder.decode_16bit_uint()),
('32int', decoder.decode_32bit_int()),
('32uint', decoder.decode_32bit_uint()),
('16float', decoder.decode_16bit_float()),
('16float2', decoder.decode_16bit_float()),
('32float', decoder.decode_32bit_float()),
('32float2', decoder.decode_32bit_float()),
('64int', decoder.decode_64bit_int()),
('64uint', decoder.decode_64bit_uint()),
('ignore', decoder.skip_bytes(8)),
('64float', decoder.decode_64bit_float()),
('64float2', decoder.decode_64bit_float()),
])

print("-" * 60)
print("Decoded Data")
print("-" * 60)
for name, value in iteritems(decoded):
print("%s\t" % name, hex(value) if isinstance(value, int) else value)

# ----------------------------------------------------------------------- #
# close the client
Expand Down
2 changes: 2 additions & 0 deletions examples/common/modbus_payload_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def run_payload_server():
builder.add_16bit_uint(0x1234)
builder.add_32bit_int(-0x1234)
builder.add_32bit_uint(0x12345678)
builder.add_16bit_float(12.34)
builder.add_16bit_float(-12.34)
builder.add_32bit_float(22.34)
builder.add_32bit_float(-22.34)
builder.add_64bit_int(-0xDEADBEEF)
Expand Down
6 changes: 3 additions & 3 deletions examples/common/synchronous_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ def run_server():
# run the server you want
# ----------------------------------------------------------------------- #
# Tcp:
StartTcpServer(context, identity=identity, address=("localhost", 5020))

StartTcpServer(context, identity=identity, address=("", 5020))
#
# TCP with different framer
# StartTcpServer(context, identity=identity,
# framer=ModbusRtuFramer, address=("0.0.0.0", 5020))
Expand All @@ -131,7 +131,7 @@ def run_server():

# RTU:
# StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
# port='/dev/ttyp0', timeout=.005, baudrate=9600)
# port='/tmp/ttyp0', timeout=.005, baudrate=9600)

# Binary
# StartSerialServer(context,
Expand Down
8 changes: 5 additions & 3 deletions pymodbus/client/asynchronous/asyncio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

DGRAM_TYPE = socket.SocketKind.SOCK_DGRAM


class BaseModbusAsyncClientProtocol(AsyncModbusClientMixin):
"""
Asyncio specific implementation of asynchronous modbus client protocol.
Expand Down Expand Up @@ -119,7 +120,7 @@ def connected(self):
def write_transport(self, packet):
return self.transport.write(packet)

def execute(self, request, **kwargs):
def _execute(self, request, **kwargs):
"""
Starts the producer to send the next request to
consumer.write(Frame(request))
Expand Down Expand Up @@ -727,7 +728,7 @@ class AsyncioModbusSerialClient(object):
framer = None

def __init__(self, port, protocol_class=None, framer=None, loop=None,
baudrate=9600, bytesize=8, parity='N', stopbits=1):
baudrate=9600, bytesize=8, parity='N', stopbits=1, **serial_kwargs):
"""
Initializes Asyncio Modbus Serial Client
:param port: Port to connect
Expand All @@ -747,6 +748,7 @@ def __init__(self, port, protocol_class=None, framer=None, loop=None,
self.parity = parity
self.stopbits = stopbits
self.framer = framer
self._extra_serial_kwargs = serial_kwargs
self._connected_event = asyncio.Event()

def stop(self):
Expand Down Expand Up @@ -780,7 +782,7 @@ def connect(self):

yield from create_serial_connection(
self.loop, self._create_protocol, self.port, baudrate=self.baudrate,
bytesize=self.bytesize, stopbits=self.stopbits, parity=self.parity
bytesize=self.bytesize, stopbits=self.stopbits, parity=self.parity, **self._extra_serial_kwargs
)
yield from self._connected_event.wait()
_logger.info('Connected to %s', self.port)
Expand Down
8 changes: 6 additions & 2 deletions pymodbus/client/asynchronous/factory/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from __future__ import absolute_import

import logging

import time
from pymodbus.client.asynchronous import schedulers
from pymodbus.client.asynchronous.thread import EventLoopThread

Expand Down Expand Up @@ -103,7 +103,11 @@ def async_io_factory(port=None, framer=None, **kwargs):

client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)
coro = client.connect()
loop.run_until_complete(coro)
if loop.is_running():
future = asyncio.run_coroutine_threadsafe(coro, loop=loop)
future.result()
else:
loop.run_until_complete(coro)
return loop, client


Expand Down
Loading