16
16
import logging
17
17
import queue
18
18
import struct
19
- from threading import Thread , Event
19
+ from threading import Event
20
20
from queue import Queue
21
21
from pyModbusTCP .server import ModbusServer
22
22
from pyModbusTCP .utils import crc16
@@ -72,21 +72,19 @@ def build(self, raw_pdu, slave_ad):
72
72
self .raw = tmp_raw
73
73
74
74
75
- class ModbusSerialWorker ( Thread ) :
76
- """ Main serial thread to manage I/O with RTU devices . """
75
+ class RtuQuery :
76
+ """ Request container to deal with modbus serial worker . """
77
77
78
- class _RtuQuery :
79
- """ Internal request container to deal with serial worker thread. """
78
+ def __init__ (self ):
79
+ self .completed = Event ()
80
+ self .request = ModbusRTUFrame ()
81
+ self .response = ModbusRTUFrame ()
80
82
81
- def __init__ (self ):
82
- self .completed = Event ()
83
- self .request = ModbusRTUFrame ()
84
- self .response = ModbusRTUFrame ()
83
+
84
+ class ModbusSerialWorker :
85
+ """ A serial worker to manage I/O with RTU devices. """
85
86
86
87
def __init__ (self , port , timeout = 1.0 , end_of_frame = 0.05 ):
87
- super ().__init__ ()
88
- # this thread is a daemon
89
- self .daemon = True
90
88
# public
91
89
self .serial_port = port
92
90
self .timeout = timeout
@@ -95,8 +93,8 @@ def __init__(self, port, timeout=1.0, end_of_frame=0.05):
95
93
# accept 5 simultaneous requests before overloaded exception is return
96
94
self .rtu_queries_q = Queue (maxsize = 5 )
97
95
98
- def run (self ):
99
- """Serial worker thread ."""
96
+ def loop (self ):
97
+ """Serial worker main loop ."""
100
98
while True :
101
99
# get next exchange from queue
102
100
rtu_query = self .rtu_queries_q .get ()
@@ -123,13 +121,13 @@ def run(self):
123
121
self .rtu_queries_q .task_done ()
124
122
125
123
def srv_engine_entry (self , session_data ):
126
- """Server engine entry point (pass request to serial worker thread ).
124
+ """Server engine entry point (pass request to serial worker queries queue ).
127
125
128
126
:param session_data: server session data
129
127
:type session_data: ModbusServer.SessionData
130
128
"""
131
129
# init a serial exchange from session data
132
- rtu_query = ModbusSerialWorker . _RtuQuery ()
130
+ rtu_query = RtuQuery ()
133
131
rtu_query .request .build (raw_pdu = session_data .request .pdu .raw ,
134
132
slave_ad = session_data .request .mbap .unit_id )
135
133
try :
@@ -169,14 +167,16 @@ def srv_engine_entry(self, session_data):
169
167
# init serial port
170
168
logger .debug ('Open serial port %s at %d bauds' , args .device , args .baudrate )
171
169
serial_port = Serial (port = args .device , baudrate = args .baudrate )
172
- # start serial worker thread
173
- logger .debug ('Start serial worker thread' )
170
+ # init serial worker
174
171
serial_worker = ModbusSerialWorker (serial_port , args .timeout , args .eof )
175
- serial_worker .start ()
176
172
# start modbus server with custom engine
177
173
logger .debug ('Start modbus server (%s, %d)' , args .host , args .port )
178
- srv = ModbusServer (host = args .host , port = args .port , ext_engine = serial_worker .srv_engine_entry )
174
+ srv = ModbusServer (host = args .host , port = args .port ,
175
+ no_block = True , ext_engine = serial_worker .srv_engine_entry )
179
176
srv .start ()
177
+ # start serial worker loop
178
+ logger .debug ('Start serial worker' )
179
+ serial_worker .loop ()
180
180
except serialutil .SerialException as e :
181
181
logger .critical ('Serial device error: %r' , e )
182
182
exit (1 )
0 commit comments