我已经实现了一个pymodbus TcpServer,它根据一些UART通信更新了它的上下文。我使用LoopingCall
进行UART通信并更新modbus上下文。在LoopingCall
期间,我发送了一些UART消息并等待适当的答案。您可以看到缩短和简化的代码(请注意,代码不会以这种方式运行,但我希望您能看到我的工作方式)。
#!/usr/bin/env python
'''
Pymodbus Server With Updating Thread
--------------------------------------------------------------------------
This is an example of having a background thread updating the
context while the server is operating. This can also be done with
a python thread::
from threading import Thread
thread = Thread(target=updating_writer, args=(context,))
thread.start()
'''
#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
from pymodbus.server.async import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
#---------------------------------------------------------------------------#
# import the twisted libraries we need
#---------------------------------------------------------------------------#
from twisted.internet.task import LoopingCall
#---------------------------------------------------------------------------#
# define your callback process
#---------------------------------------------------------------------------#
def updating_writer(a):
context = a[0]
register = 3
slave_id = 0x00
address = 0x10
_ser_ = serial.Serial(
#port = '/dev/ttyUSB0',
port = dev,
baudrate=115200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
_ser_.open()
_ser_.write("Example")
inbuff = []
values = []
@timeout(0.1)
while True:
inbuff.append(_ser_.read(1))
# come kind of checksum calculation, to check if message is complete
if checkmessage(inbuff):
values = ord(inbuff[0])
break
context[slave_id].setValues(register, address, values)
#---------------------------------------------------------------------------#
# initialize your data store
#---------------------------------------------------------------------------#
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [17]*100),
co = ModbusSequentialDataBlock(0, [17]*100),
hr = ModbusSequentialDataBlock(0, [17]*100),
ir = ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#
identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.0'
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
time = 5 # 5 seconds delay
loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False) # initially delay by time
StartTcpServer(context, identity=identity, address=("localhost", 5020))
只是为了完整性,这里是超时功能(我在Stackoverflow上找到了类似的例子)。
from functools import wraps
import errno
import os
import signal
class TimeoutError(Exception):
pass
def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
#signal.alarm(seconds)
signal.setitimer(signal.ITIMER_REAL,seconds)
try:
result = func(*args, **kwargs)
finally:
#signal.alarm(0)
signal.setitimer(signal.ITIMER_REAL,0)
return result
return wraps(func)(wrapper)
return decorator
对我来说,似乎pymodbus TcpServer在LoopingCall
操作(updating_writer()
)期间冻结。
这个LoopingCall
是否在自己的线程中运行,还是阻止pymodbus TcpServer操作?我怎样才能实现这一点,以便TcpServer不会冻结?
顺便说一句:这段代码在raspberry jessie和python-2.7上覆盖着树莓。
编辑:我想我需要修改我的问题,因为根据Twisted LoopingCall with blocking function LoopingCall
似乎在主线程中运行并阻止其他操作。
如何修改我的代码,以便在更新任务期间不会阻止pymodbus TcpServer?