Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit 7db7b15

Browse files
committed
Variable lenght request and formatting
1 parent 08a99b7 commit 7db7b15

File tree

2 files changed

+79
-116
lines changed

2 files changed

+79
-116
lines changed

main.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,36 @@
55

66
######################### READ COILS #########################
77
#slave_addr=0x0A
8-
#starting_address=0x00
9-
#coil_quantity=20
8+
#starting_address=0x01
9+
#coil_quantity=100
1010

1111
#coil_status = serial_obj.read_coils(slave_addr, starting_address, coil_quantity)
12-
#print('Coil status: ' + ' '.join('{:#010b}'.format(x) for x in coil_status))
12+
#print('Coil status: ' + ' '.join('{:x}'.format(x) for x in coil_status))
1313

1414
###################### READ DISCRETE INPUTS ##################
1515
#slave_addr=0x0A
16-
#starting_address=0x00
17-
#input_quantity=20
16+
#starting_address=0x9
17+
#input_quantity=100
1818

1919
#input_status = serial_obj.read_discrete_inputs(slave_addr, starting_address, input_quantity)
20-
#print('Input status: ' + ' '.join('{:#010b}'.format(x) for x in input_status))
20+
#print('Input status: ' + ' '.join('{:x}'.format(x) for x in input_status))
2121

2222
###################### READ HOLDING REGISTERS ##################
2323
#slave_addr=0x0A
2424
#starting_address=0x00
25-
#register_quantity=20
25+
#register_quantity=100
26+
#signed=False
2627

27-
#register_value = serial_obj.read_holding_registers(slave_addr, starting_address, register_quantity, True)
28+
#register_value = serial_obj.read_holding_registers(slave_addr, starting_address, register_quantity, signed)
2829
#print('Holding register value: ' + ' '.join('0x{:02X}'.format(x) for x in register_value))
2930

3031
###################### READ INPUT REGISTERS ##################
3132
#slave_addr=0x0A
3233
#starting_address=0x00
3334
#register_quantity=20
35+
#signed=True
3436

35-
#register_value = serial_obj.read_input_registers(slave_addr, starting_address, register_quantity, True)
37+
#register_value = serial_obj.read_input_registers(slave_addr, starting_address, register_quantity, signed)
3638
#print('Input register value: ' + ' '.join('0x{:02X}'.format(x) for x in register_value))
3739

3840
###################### WRITE SINGLE COIL ##################
@@ -48,15 +50,16 @@
4850
#slave_addr=0x0A
4951
#register_address=0x01
5052
#register_value=-32768
53+
#signed=True
5154

52-
#return_flag = serial_obj.write_single_register(slave_addr, register_address, register_value, True)
55+
#return_flag = serial_obj.write_single_register(slave_addr, register_address, register_value, signed)
5356
#output_flag = 'Success' if return_flag else 'Failure'
5457
#print('Writing single coil status: ' + output_flag)
5558

5659
###################### WRITE MULIPLE COILS ##################
5760
#slave_addr=0x0A
5861
#starting_address=0x00
59-
#output_values=[1,1,1,0,0,0,0,0,1,0,0,0]
62+
#output_values=[1,1,1,0,0,1,1,1,0,0,1,1,1]
6063

6164
#return_flag = serial_obj.write_multiple_coils(slave_addr, starting_address, output_values)
6265
#output_flag = 'Success' if return_flag else 'Failure'

uModbus/serial.py

Lines changed: 65 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
class Serial:
88

99
_uart = None
10-
_slave_addr = None
1110

1211
def __init__(self, uart_id, baudrate=9600, data_bits=8, stop_bits=1, parity=None, pins=None):
1312
self._uart = UART(uart_id, baudrate = baudrate, bits = data_bits, parity = parity, \
@@ -21,22 +20,46 @@ def _calculate_crc16(self, data):
2120

2221
return struct.pack('<H',crc)
2322

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+
2433
def _uart_read(self):
25-
response = None
34+
response = bytearray()
2635

2736
for x in range(1, 10):
2837
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
3142
time.sleep(0.1)
3243

3344
return response
3445

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)
3653

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:]
3861
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]):
4063
raise OSError('Invalid response CRC')
4164

4265
if (response[0] != slave_addr):
@@ -45,9 +68,9 @@ def _validate_resp_hdr(self, response, slave_addr, function_code, has_count=Fals
4568
if (response[1] == (function_code + Const.ERROR_BIAS)):
4669
raise ValueError('Slave returned exception code: {:d}'.format(response[2]))
4770

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
4972

50-
return response[header_length : len(response) - Const.CRC_LENGTH]
73+
return response[hdr_length : len(response) - Const.CRC_LENGTH]
5174

5275
def _validate_resp_data(self, data, function_code, address, value=None, quantity=None, signed = True):
5376
if function_code in [Const.WRITE_SINGLE_COIL, Const.WRITE_SINGLE_REGISTER]:
@@ -69,64 +92,46 @@ def _to_short(self, byte_array, signed = True):
6992
response_quantity = int(len(byte_array) / 2)
7093
fmt = '>' + (('h' if signed else 'H') * response_quantity)
7194

72-
return list(struct.unpack(fmt, byte_array))
95+
return struct.unpack(fmt, byte_array)
7396

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)])
75101

76-
modbus_serial_pdu = bytearray()
77-
modbus_serial_pdu.append(slave_addr)
102+
return bool_list
78103

104+
def read_coils(self, slave_addr, starting_addr, coil_qty):
79105
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)
85107

86-
self._uart.write(modbus_serial_pdu)
87-
response = self._uart_read()
108+
response = self._send_receive(modbus_pdu, slave_addr)
88109

89-
coil_status_pdu = None
110+
status_pdu = None
90111
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)
92114

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
99116

117+
def read_discrete_inputs(self, slave_addr, starting_addr, input_qty):
100118
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)
103120

104-
crc = self._calculate_crc16(modbus_serial_pdu)
105-
modbus_serial_pdu.extend(crc)
121+
response = self._send_receive(modbus_pdu, slave_addr)
106122

107-
self._uart.write(modbus_serial_pdu)
108-
response = self._uart_read()
109-
110-
input_status_pdu = None
123+
status_pdu = None
111124
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)
115127

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
120129

130+
def read_holding_registers(self, slave_addr, starting_addr, register_qty, signed = True):
121131
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)
127133

128-
self._uart.write(modbus_serial_pdu)
129-
response = self._uart_read()
134+
response = self._send_receive(modbus_pdu, slave_addr)
130135

131136
register_value = None
132137
if (response is not None):
@@ -136,19 +141,10 @@ def read_holding_registers(self, slave_addr, starting_address, register_quantity
136141
return register_value
137142

138143
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-
143144
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)
149146

150-
self._uart.write(modbus_serial_pdu)
151-
response = self._uart_read()
147+
response = self._send_receive(modbus_pdu, slave_addr)
152148

153149
register_value = None
154150
if (response is not None):
@@ -158,19 +154,10 @@ def read_input_registers(self, slave_addr, starting_address, register_quantity,
158154
return register_value
159155

160156
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-
165157
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)
168159

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)
174161

175162
operation_status = False
176163
if (response is not None):
@@ -181,19 +168,10 @@ def write_single_coil(self, slave_addr, output_address, output_value):
181168
return operation_status
182169

183170
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-
188171
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)
191173

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)
197175

198176
operation_status = False
199177
if (response is not None):
@@ -204,19 +182,10 @@ def write_single_register(self, slave_addr, register_address, register_value, si
204182
return operation_status
205183

206184
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-
211185
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)
217187

218-
self._uart.write(modbus_serial_pdu)
219-
response = self._uart_read()
188+
response = self._send_receive(modbus_pdu, slave_addr)
220189

221190
operation_status = False
222191
if (response is not None):
@@ -227,19 +196,10 @@ def write_multiple_coils(self, slave_addr, starting_address, output_values):
227196
return operation_status
228197

229198
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-
234199
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)
240201

241-
self._uart.write(modbus_serial_pdu)
242-
response = self._uart_read()
202+
response = self._send_receive(modbus_pdu, slave_addr)
243203

244204
operation_status = False
245205
if (response is not None):

0 commit comments

Comments
 (0)