7
7
class Serial :
8
8
9
9
_uart = None
10
- _slave_addr = None
11
10
12
11
def __init__ (self , uart_id , baudrate = 9600 , data_bits = 8 , stop_bits = 1 , parity = None , pins = None ):
13
12
self ._uart = UART (uart_id , baudrate = baudrate , bits = data_bits , parity = parity , \
@@ -21,22 +20,46 @@ def _calculate_crc16(self, data):
21
20
22
21
return struct .pack ('<H' ,crc )
23
22
23
+ def _exit_read (self , response ):
24
+
25
+ if response [1 ] in [Const .READ_COILS , Const .READ_DISCRETE_INPUTS , Const .READ_HOLDING_REGISTERS ,
26
+ Const .READ_INPUT_REGISTER ]:
27
+ expected_len = Const .RESPONSE_HDR_LENGTH + 1 + response [2 ] + Const .CRC_LENGTH
28
+ if len (response ) < expected_len :
29
+ return False
30
+
31
+ return True
32
+
24
33
def _uart_read (self ):
25
- response = None
34
+ response = bytearray ()
26
35
27
36
for x in range (1 , 10 ):
28
37
if self ._uart .any ():
29
- response = self ._uart .readall ()
30
- break
38
+ response .extend (self ._uart .readall ())
39
+ # Variable length requests may require multiple reads
40
+ if self ._exit_read (response ):
41
+ break
31
42
time .sleep (0.1 )
32
43
33
44
return response
34
45
35
- def _validate_resp_hdr (self , response , slave_addr , function_code , has_count = False ):
46
+ def _send_receive (self , modbus_pdu , slave_addr ):
47
+ serial_pdu = bytearray ()
48
+ serial_pdu .append (slave_addr )
49
+ serial_pdu .extend (modbus_pdu )
50
+
51
+ crc = self ._calculate_crc16 (serial_pdu )
52
+ serial_pdu .extend (crc )
36
53
37
- response_crc = response [- Const .CRC_LENGTH :]
54
+ self ._uart .write (serial_pdu )
55
+
56
+ return self ._uart_read ()
57
+
58
+ def _validate_resp_hdr (self , response , slave_addr , function_code , count = False ):
59
+
60
+ resp_crc = response [- Const .CRC_LENGTH :]
38
61
expected_crc = self ._calculate_crc16 (response [0 :len (response ) - Const .CRC_LENGTH ])
39
- if (response_crc != expected_crc ):
62
+ if (resp_crc [ 0 ] != expected_crc [ 0 ]) or ( resp_crc [ 1 ] != expected_crc [ 1 ] ):
40
63
raise OSError ('Invalid response CRC' )
41
64
42
65
if (response [0 ] != slave_addr ):
@@ -45,9 +68,9 @@ def _validate_resp_hdr(self, response, slave_addr, function_code, has_count=Fals
45
68
if (response [1 ] == (function_code + Const .ERROR_BIAS )):
46
69
raise ValueError ('Slave returned exception code: {:d}' .format (response [2 ]))
47
70
48
- header_length = Const .RESPONSE_HDR_LENGTH + 1 if has_count else Const .RESPONSE_HDR_LENGTH
71
+ hdr_length = Const .RESPONSE_HDR_LENGTH + 1 if count else Const .RESPONSE_HDR_LENGTH
49
72
50
- return response [header_length : len (response ) - Const .CRC_LENGTH ]
73
+ return response [hdr_length : len (response ) - Const .CRC_LENGTH ]
51
74
52
75
def _validate_resp_data (self , data , function_code , address , value = None , quantity = None , signed = True ):
53
76
if function_code in [Const .WRITE_SINGLE_COIL , Const .WRITE_SINGLE_REGISTER ]:
@@ -69,64 +92,46 @@ def _to_short(self, byte_array, signed = True):
69
92
response_quantity = int (len (byte_array ) / 2 )
70
93
fmt = '>' + (('h' if signed else 'H' ) * response_quantity )
71
94
72
- return list ( struct .unpack (fmt , byte_array ) )
95
+ return struct .unpack (fmt , byte_array )
73
96
74
- def read_coils (self , slave_addr , starting_address , coil_quantity ):
97
+ def _bytes_to_bool (self , byte_list ):
98
+ bool_list = []
99
+ for index , byte in enumerate (byte_list ):
100
+ bool_list .extend ([bool (byte & (1 << n )) for n in range (8 )])
75
101
76
- modbus_serial_pdu = bytearray ()
77
- modbus_serial_pdu .append (slave_addr )
102
+ return bool_list
78
103
104
+ def read_coils (self , slave_addr , starting_addr , coil_qty ):
79
105
functions = Functions ()
80
- request = functions .read_coils (starting_address , coil_quantity )
81
- modbus_serial_pdu .extend (request )
82
-
83
- crc = self ._calculate_crc16 (modbus_serial_pdu )
84
- modbus_serial_pdu .extend (crc )
106
+ modbus_pdu = functions .read_coils (starting_addr , coil_qty )
85
107
86
- self ._uart .write (modbus_serial_pdu )
87
- response = self ._uart_read ()
108
+ response = self ._send_receive (modbus_pdu , slave_addr )
88
109
89
- coil_status_pdu = None
110
+ status_pdu = None
90
111
if (response is not None ):
91
- coil_status_pdu = self ._validate_resp_hdr (response , slave_addr , Const .READ_COILS , True )
112
+ pdu_bytes = self ._validate_resp_hdr (response , slave_addr , Const .READ_COILS , True )
113
+ status_pdu = self ._bytes_to_bool (pdu_bytes )
92
114
93
- return coil_status_pdu
94
-
95
- def read_discrete_inputs (self , slave_addr , starting_address , input_quantity ):
96
-
97
- modbus_serial_pdu = bytearray ()
98
- modbus_serial_pdu .append (slave_addr )
115
+ return status_pdu
99
116
117
+ def read_discrete_inputs (self , slave_addr , starting_addr , input_qty ):
100
118
functions = Functions ()
101
- request = functions .read_discrete_inputs (starting_address , input_quantity )
102
- modbus_serial_pdu .extend (request )
119
+ modbus_pdu = functions .read_discrete_inputs (starting_addr , input_qty )
103
120
104
- crc = self ._calculate_crc16 (modbus_serial_pdu )
105
- modbus_serial_pdu .extend (crc )
121
+ response = self ._send_receive (modbus_pdu , slave_addr )
106
122
107
- self ._uart .write (modbus_serial_pdu )
108
- response = self ._uart_read ()
109
-
110
- input_status_pdu = None
123
+ status_pdu = None
111
124
if (response is not None ):
112
- input_status_pdu = self ._validate_resp_hdr (response , slave_addr , Const .READ_DISCRETE_INPUTS , True )
113
-
114
- return input_status_pdu
125
+ pdu_bytes = self ._validate_resp_hdr (response , slave_addr , Const .READ_DISCRETE_INPUTS , True )
126
+ status_pdu = self ._bytes_to_bool (pdu_bytes )
115
127
116
- def read_holding_registers (self , slave_addr , starting_address , register_quantity , signed = True ):
117
-
118
- modbus_serial_pdu = bytearray ()
119
- modbus_serial_pdu .append (slave_addr )
128
+ return status_pdu
120
129
130
+ def read_holding_registers (self , slave_addr , starting_addr , register_qty , signed = True ):
121
131
functions = Functions ()
122
- request = functions .read_holding_registers (starting_address , register_quantity )
123
- modbus_serial_pdu .extend (request )
124
-
125
- crc = self ._calculate_crc16 (modbus_serial_pdu )
126
- modbus_serial_pdu .extend (crc )
132
+ modbus_pdu = functions .read_holding_registers (starting_addr , register_qty )
127
133
128
- self ._uart .write (modbus_serial_pdu )
129
- response = self ._uart_read ()
134
+ response = self ._send_receive (modbus_pdu , slave_addr )
130
135
131
136
register_value = None
132
137
if (response is not None ):
@@ -136,19 +141,10 @@ def read_holding_registers(self, slave_addr, starting_address, register_quantity
136
141
return register_value
137
142
138
143
def read_input_registers (self , slave_addr , starting_address , register_quantity , signed = True ):
139
-
140
- modbus_serial_pdu = bytearray ()
141
- modbus_serial_pdu .append (slave_addr )
142
-
143
144
functions = Functions ()
144
- request = functions .read_input_registers (starting_address , register_quantity )
145
- modbus_serial_pdu .extend (request )
146
-
147
- crc = self ._calculate_crc16 (modbus_serial_pdu )
148
- modbus_serial_pdu .extend (crc )
145
+ modbus_pdu = functions .read_input_registers (starting_address , register_quantity )
149
146
150
- self ._uart .write (modbus_serial_pdu )
151
- response = self ._uart_read ()
147
+ response = self ._send_receive (modbus_pdu , slave_addr )
152
148
153
149
register_value = None
154
150
if (response is not None ):
@@ -158,19 +154,10 @@ def read_input_registers(self, slave_addr, starting_address, register_quantity,
158
154
return register_value
159
155
160
156
def write_single_coil (self , slave_addr , output_address , output_value ):
161
-
162
- modbus_serial_pdu = bytearray ()
163
- modbus_serial_pdu .append (slave_addr )
164
-
165
157
functions = Functions ()
166
- request = functions .write_single_coil (output_address , output_value )
167
- modbus_serial_pdu .extend (request )
158
+ modbus_pdu = functions .write_single_coil (output_address , output_value )
168
159
169
- crc = self ._calculate_crc16 (modbus_serial_pdu )
170
- modbus_serial_pdu .extend (crc )
171
-
172
- self ._uart .write (modbus_serial_pdu )
173
- response = self ._uart_read ()
160
+ response = self ._send_receive (modbus_pdu , slave_addr )
174
161
175
162
operation_status = False
176
163
if (response is not None ):
@@ -181,19 +168,10 @@ def write_single_coil(self, slave_addr, output_address, output_value):
181
168
return operation_status
182
169
183
170
def write_single_register (self , slave_addr , register_address , register_value , signed = True ):
184
-
185
- modbus_serial_pdu = bytearray ()
186
- modbus_serial_pdu .append (slave_addr )
187
-
188
171
functions = Functions ()
189
- request = functions .write_single_register (register_address , register_value , signed )
190
- modbus_serial_pdu .extend (request )
172
+ modbus_pdu = functions .write_single_register (register_address , register_value , signed )
191
173
192
- crc = self ._calculate_crc16 (modbus_serial_pdu )
193
- modbus_serial_pdu .extend (crc )
194
-
195
- self ._uart .write (modbus_serial_pdu )
196
- response = self ._uart_read ()
174
+ response = self ._send_receive (modbus_pdu , slave_addr )
197
175
198
176
operation_status = False
199
177
if (response is not None ):
@@ -204,19 +182,10 @@ def write_single_register(self, slave_addr, register_address, register_value, si
204
182
return operation_status
205
183
206
184
def write_multiple_coils (self , slave_addr , starting_address , output_values ):
207
-
208
- modbus_serial_pdu = bytearray ()
209
- modbus_serial_pdu .append (slave_addr )
210
-
211
185
functions = Functions ()
212
- request = functions .write_multiple_coils (starting_address , output_values )
213
- modbus_serial_pdu .extend (request )
214
-
215
- crc = self ._calculate_crc16 (modbus_serial_pdu )
216
- modbus_serial_pdu .extend (crc )
186
+ modbus_pdu = functions .write_multiple_coils (starting_address , output_values )
217
187
218
- self ._uart .write (modbus_serial_pdu )
219
- response = self ._uart_read ()
188
+ response = self ._send_receive (modbus_pdu , slave_addr )
220
189
221
190
operation_status = False
222
191
if (response is not None ):
@@ -227,19 +196,10 @@ def write_multiple_coils(self, slave_addr, starting_address, output_values):
227
196
return operation_status
228
197
229
198
def write_multiple_registers (self , slave_addr , starting_address , register_values , signed = True ):
230
-
231
- modbus_serial_pdu = bytearray ()
232
- modbus_serial_pdu .append (slave_addr )
233
-
234
199
functions = Functions ()
235
- request = functions .write_multiple_registers (starting_address , register_values , signed )
236
- modbus_serial_pdu .extend (request )
237
-
238
- crc = self ._calculate_crc16 (modbus_serial_pdu )
239
- modbus_serial_pdu .extend (crc )
200
+ modbus_pdu = functions .write_multiple_registers (starting_address , register_values , signed )
240
201
241
- self ._uart .write (modbus_serial_pdu )
242
- response = self ._uart_read ()
202
+ response = self ._send_receive (modbus_pdu , slave_addr )
243
203
244
204
operation_status = False
245
205
if (response is not None ):
0 commit comments