Skip to content

Commit 44d17a1

Browse files
committed
libs/modbus: Unit ID mismatch problem.
Signed-off-by: lbuque <1102390310@qq.com>
1 parent 6c94995 commit 44d17a1

File tree

3 files changed

+487
-437
lines changed

3 files changed

+487
-437
lines changed

m5stack/libs/modbus/modbus/frame.py

Lines changed: 101 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,27 @@
77
class ModbusFrame:
88
def __init__(
99
self,
10-
func_code=0,
11-
register=None,
12-
fr_type="request",
13-
length=None,
14-
data=None,
15-
error_code=None,
16-
):
10+
func_code: int = 0,
11+
register: int = None,
12+
fr_type: str = "request",
13+
length: int = None,
14+
data: bytearray = None,
15+
error_code: int = None,
16+
) -> None:
1717
"""Init a generic modbus frame.
1818
19-
Args:
20-
func_code (int, optional): Function Code. Defaults to 0.
21-
register (int, optional): Register. Defaults to None.
22-
fr_type (str, optional): Type of Frame (request or response).
23-
Defaults to "request".
24-
length (int, optional): Number of registers. Defaults to None.
25-
data (bytearray, optional): Data. Defaults to None.
26-
error_code (int, optional): Error Code. Defaults to None.
19+
:param int func_code: Function code (1-6,15,16). Defaults to 0.
20+
:param register: Register. Defaults to None.
21+
:type register: int or None
22+
:param fr_type: Frame type (request/response). Defaults to "request".
23+
:type fr_type: str or None
24+
:param length: Length of requested data. Defaults to None.
25+
:type length: int or None
26+
:param data: Payload. Defaults to None.
27+
:type data: bytearray or None
28+
:param error_code: Error Code. Defaults to None.
29+
:type error_code: int or None
30+
2731
"""
2832

2933
self.type = fr_type
@@ -108,7 +112,7 @@ def __init__(
108112
self.pdu = None
109113
self.frame = None
110114

111-
def _create_pdu(self):
115+
def _create_pdu(self) -> None:
112116
self.pdu = bytearray([])
113117
self.pdu += bytearray([self.func_code])
114118

@@ -133,40 +137,40 @@ def _create_pdu(self):
133137
if self.func_code in [0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x8F, 0x90]:
134138
self.pdu += bytearray([self.error_code])
135139

136-
def _create_frame(self):
140+
def _create_frame(self) -> None:
137141
"""Override in derived Class"""
138142
pass
139143

140-
def get_frame(self):
144+
def get_frame(self) -> bytearray:
141145
if self.frame is None:
142146
self._create_frame()
143147
return self.frame
144148

145149

146150
class ModbusRTUFrame(ModbusFrame):
147-
def __init__(self, device_addr=0, verbose: bool = False, *args, **kwargs):
151+
def __init__(self, device_addr: int = 0, verbose: bool = False, *args, **kwargs) -> None:
148152
"""Create modbus rtu frame.
149153
150-
Args:
151-
device_addr (int, optional): Slave address. Defaults to 0.
152-
func_code (int, optional): Function code (1-6,15,16). Defaults to 0.
153-
register ([type], optional): Register. Defaults to None.
154-
fr_type (str, optional): Frame type (request/response). Defaults to "request".
155-
length ([type], optional): Length of reqested data. Defaults to None.
156-
data ([type], optional): Payload. Defaults to None.
154+
:param int device_addr: Slave address. Defaults to 0.
155+
:param bool verbose: If True, print debug information. Defaults to False.
156+
:param int func_code: Function code (1-6,15,16). Defaults to 0.
157+
:param int register: Register. Defaults to None.
158+
:param str fr_type: Frame type (request/response). Defaults to "request".
159+
:param int length: Length of requested data. Defaults to None.
160+
:param bytes data: Payload. Defaults to None.
157161
"""
158162
super(ModbusRTUFrame, self).__init__(*args, **kwargs)
159163
self._verbose = verbose
160164
self.device_addr = device_addr
161165
self.frame = None
162166

163-
def _create_frame(self):
167+
def _create_frame(self) -> None:
164168
self._create_pdu()
165169
self.frame = bytearray([self.device_addr]) + self.pdu
166170
crc = ModbusRTUFrame._crc16(self.frame)
167171
self.frame += bytearray([crc & 0xFF, crc >> 8])
168172

169-
def __str__(self):
173+
def __str__(self) -> str:
170174
return "<ModbusRTUFrame ({}): device: {}, func_code: {}, frame:{}>".format(
171175
self.type,
172176
self.device_addr,
@@ -175,7 +179,7 @@ def __str__(self):
175179
)
176180

177181
@classmethod
178-
def _crc16(cls, data):
182+
def _crc16(cls, data: bytearray) -> int:
179183
offset = 0
180184
length = len(data)
181185
if data is None or offset < 0 or offset > len(data) - 1 and offset + length > len(data):
@@ -191,15 +195,18 @@ def _crc16(cls, data):
191195
return crc
192196

193197
@classmethod
194-
def parse_frame(cls, frame, fr_type=None, verbose=False):
195-
"""Factory Method: Create a ModbusRTUFrame from bytearray.
196-
197-
Args:
198-
frame (bytearray): frame to parse.
199-
fr_type (str, optional): request, response, or None
200-
201-
Returns:
202-
ModbusRTUFrame: parsed frame
198+
def parse_frame(
199+
cls, frame: bytearray, fr_type: str = None, verbose: bool = False
200+
) -> "ModbusRTUFrame":
201+
"""Create a ModbusRTUFrame from bytearray.
202+
203+
:param bytearray frame: The frame to parse.
204+
:param str fr_type: Type of frame, either "request", "response", or
205+
None. If None, it will try to determine the type
206+
automatically.
207+
:param bool verbose: If True, print debug information.
208+
:return: ModbusRTUFrame object if parsing was successful, None otherwise.
209+
:rtype: ModbusRTUFrame or None
203210
"""
204211

205212
verbose and print("Parsing RTU frame: " + " ".join(["{:02x}".format(x) for x in frame]))
@@ -278,15 +285,14 @@ def parse_frame(cls, frame, fr_type=None, verbose=False):
278285
# raise ValueError("Could not parse Frame " + " ".join(["{:02x}".format(x) for x in frame]))
279286

280287
@classmethod
281-
def _check_both(cls, frame):
282-
"""Parser-Helper: if func_code is 0x05 or 0x06, we can't decide if it is a
283-
request or a response. This method checks, if is a valid 0x05- or 0x06-frame.
288+
def _check_both(cls, frame: bytearray) -> bool:
289+
"""if func_code is 0x05 or 0x06, we can't decide if it is a request or a
290+
response. This method checks, if is a valid 0x05- or 0x06-frame.
284291
285-
Args:
286-
frame (bytearray): The frame to check.
292+
:param bytearray frame: The frame to check.
287293
288-
Returns:
289-
bool: True, if it is a valid 0x05- or 0x06-frame.
294+
:return: True, if it is a valid 0x05- or 0x06-frame.
295+
:rtype: bool
290296
"""
291297
try:
292298
func_code = frame[1]
@@ -297,15 +303,13 @@ def _check_both(cls, frame):
297303
return False
298304

299305
@classmethod
300-
def _check_request(cls, frame):
301-
"""Parser-Helper: This method checks, if is a valid request. It returns False,
306+
def _check_request(cls, frame: bytearray) -> bool:
307+
"""This method checks, if is a valid request. It returns False,
302308
if the frame could be a request or a response.
303309
304-
Args:
305-
frame (bytearray): The frame to check.
306-
307-
Returns:
308-
bool: True, if it is a valid request.
310+
:param bytearray frame: The frame to check.
311+
:return: True, if it is a valid request.
312+
:rtype: bool
309313
"""
310314
try:
311315
func_code = frame[1]
@@ -321,15 +325,13 @@ def _check_request(cls, frame):
321325
return False
322326

323327
@classmethod
324-
def _check_response(cls, frame):
325-
"""Parser-Helper: This method checks, if is a valid response. It returns False,
328+
def _check_response(cls, frame: bytearray) -> bool:
329+
"""This method checks, if is a valid response. It returns False,
326330
if the frame could be a request or a response.
327331
328-
Args:
329-
frame (bytearray): The frame to check.
330-
331-
Returns:
332-
bool: True, if it is a valid response.
332+
:param bytearray frame: The frame to check.
333+
:return: True, if it is a valid response.
334+
:rtype: bool
333335
"""
334336
try:
335337
func_code = frame[1]
@@ -345,14 +347,12 @@ def _check_response(cls, frame):
345347
return False
346348

347349
@classmethod
348-
def transform_frame(cls, tcp_frame):
350+
def transform_frame(cls, tcp_frame: "ModbusTCPFrame") -> "ModbusRTUFrame":
349351
"""transform a tcp-frame to a rtu-frame and copy all data
350352
351-
Args:
352-
tcp_frame (ModbusTCPFrame): tcp-frame
353-
354-
Returns:
355-
ModbusRTUFrame
353+
:param ModbusTCPFrame tcp_frame: tcp-frame to transform
354+
:return: ModbusRTUFrame object with data from tcp_frame
355+
:rtype: ModbusRTUFrame
356356
"""
357357
frame = ModbusRTUFrame()
358358
frame.data = tcp_frame.data
@@ -365,24 +365,27 @@ def transform_frame(cls, tcp_frame):
365365

366366

367367
class ModbusTCPFrame(ModbusFrame):
368-
def __init__(self, transaction_id=0, unit_id=0, *args, **kwargs):
368+
def __init__(self, transaction_id: int = 0, unit_id: int = 0, *args, **kwargs) -> None:
369369
"""Create modbus tcp frame.
370370
371-
Args:
372-
transaction_id (int, optional): Transaction ID. Defaults to 0.
373-
unit_id (int, optional): Unit address. Defaults to 0.
374-
func_code (int, optional): Function code (1-6,15,16). Defaults to 0.
375-
register ([type], optional): Register. Defaults to None.
376-
fr_type (str, optional): Frame type (request/response). Defaults to "request".
377-
length ([type], optional): Length of reqested data. Defaults to None.
378-
data ([type], optional): Payload. Defaults to None.
371+
:param int transaction_id: Transaction ID. Defaults to 0.
372+
:param int unit_id: Unit address. Defaults to 0.
373+
:param int func_code: Function code (1-6,15,16). Defaults to 0.
374+
:param register: Register. Defaults to None.
375+
:type register: int or None
376+
:param fr_type: Frame type (request/response). Defaults to "request".
377+
:type fr_type: str or None
378+
:param length: Length of requested data. Defaults to None.
379+
:type length: int or None
380+
:param data: Payload. Defaults to None.
381+
:type data: bytearray or None
379382
"""
380383
super(ModbusTCPFrame, self).__init__(*args, **kwargs)
381384
self.transaction_id = transaction_id
382385
self.unit_id = unit_id
383386
self.frame = None
384387

385-
def _create_frame(self):
388+
def _create_frame(self) -> None:
386389
self._create_pdu()
387390
self.frame = bytearray([self.transaction_id >> 8, self.transaction_id & 0xFF])
388391
self.frame += bytearray([0x00, 0x00]) # Protocol ID
@@ -391,20 +394,19 @@ def _create_frame(self):
391394
self.frame += bytearray([self.unit_id])
392395
self.frame += self.pdu
393396

394-
def __str__(self):
397+
def __str__(self) -> str:
395398
return "<ModbusTCPFrame ({}): func_code: {}, frame:{}>".format(
396399
self.type, self.func_code, " ".join(["{:02x}".format(x) for x in self.get_frame()])
397400
)
398401

399402
@classmethod
400-
def parse_frame(cls, frame, verbose=False):
401-
"""Factory Method: Create a ModbusTCPFrame from bytearray.
403+
def parse_frame(cls, frame: bytearray, verbose: bool = False) -> "ModbusTCPFrame":
404+
"""Create a ModbusTCPFrame from bytearray.
402405
403-
Args:
404-
frame (bytearray): frame to parse.
405-
406-
Returns:
407-
ModbusTCPFrame: parsed frame
406+
:param bytearray frame: The frame to parse.
407+
:param bool verbose: If True, print debug information.
408+
:return: ModbusTCPFrame object if parsing was successful, None otherwise.
409+
:rtype: ModbusTCPFrame or None
408410
"""
409411

410412
verbose and print("Parsing TCP frame: " + " ".join(["{:02x}".format(x) for x in frame]))
@@ -454,7 +456,7 @@ def parse_frame(cls, frame, verbose=False):
454456

455457
f = None
456458
if cls._check_response(frame, length):
457-
verbose and print("frame is request")
459+
verbose and print("frame is response")
458460
if func_code in [0x01, 0x02, 0x03, 0x04]:
459461
bc = frame[8]
460462
data = frame[9 : 9 + bc]
@@ -492,15 +494,13 @@ def parse_frame(cls, frame, verbose=False):
492494
# raise ValueError("Could not parse Frame " + " ".join(["{:02x}".format(x) for x in frame]))
493495

494496
@classmethod
495-
def _check_both(cls, frame, length):
496-
"""Parser-Helper: if func_code is 0x05 or 0x06, we can't decide if it is a
497+
def _check_both(cls, frame: bytearray, length: int) -> bool:
498+
"""if func_code is 0x05 or 0x06, we can't decide if it is a
497499
request or a response. This method checks, if is a valid 0x05- or 0x06-frame.
498500
499-
Args:
500-
frame (bytearray): The frame to check.
501-
502-
Returns:
503-
bool: True, if it is a valid 0x05- or 0x06-frame.
501+
:param bytearray frame: The frame to check.
502+
:returns: True, if it is a valid 0x05- or 0x06-frame.
503+
:rtype: bool
504504
"""
505505
try:
506506
func_code = frame[7]
@@ -511,15 +511,13 @@ def _check_both(cls, frame, length):
511511
return False
512512

513513
@classmethod
514-
def _check_request(cls, frame, length):
515-
"""Parser-Helper: This method checks, if is a valid request. It returns False,
514+
def _check_request(cls, frame: bytearray, length: int) -> bool:
515+
"""This method checks, if is a valid request. It returns False,
516516
if the frame could be a request or a response.
517517
518-
Args:
519-
frame (bytearray): The frame to check.
520-
521-
Returns:
522-
bool: True, if it is a valid request.
518+
:param bytearray frame: The frame to check.
519+
:returns: True, if it is a valid request.
520+
:rtype: bool
523521
"""
524522
try:
525523
func_code = frame[7]
@@ -535,15 +533,13 @@ def _check_request(cls, frame, length):
535533
return False
536534

537535
@classmethod
538-
def _check_response(cls, frame, length):
539-
"""Parser-Helper: This method checks, if is a valid response. It returns False,
536+
def _check_response(cls, frame: bytearray, length: int) -> bool:
537+
"""This method checks, if is a valid response. It returns False,
540538
if the frame could be a request or a response.
541539
542-
Args:
543-
frame (bytearray): The frame to check.
544-
545-
Returns:
546-
bool: True, if it is a valid response.
540+
:param bytearray frame: The frame to check.
541+
:returns: True, if it is a valid response.
542+
:rtype: bool
547543
"""
548544
try:
549545
func_code = frame[7]

0 commit comments

Comments
 (0)