Skip to content

Commit 1131c8d

Browse files
committed
review from github: suggested changes / formatting
1 parent 9908fa7 commit 1131c8d

2 files changed

Lines changed: 67 additions & 34 deletions

File tree

canopen/sdo/exceptions.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Union
2+
13
class SdoError(Exception):
24
pass
35

@@ -33,23 +35,23 @@ class SdoAbortedError(SdoError):
3335
0x060A0023: "Resource not available",
3436
0x08000000: "General error",
3537
0x08000020: "Data cannot be transferred or stored to the application",
36-
0x08000021: (
37-
"Data can not be transferred or stored to the application "
38-
"because of local control"
39-
),
40-
0x08000022: (
41-
"Data can not be transferred or stored to the application "
42-
"because of the present device state"
43-
),
44-
0x08000023: (
45-
"Object dictionary dynamic generation fails or no object "
46-
"dictionary is present"
47-
),
38+
0x08000021: ("Data can not be transferred or stored to the application "
39+
"because of local control"),
40+
0x08000022: ("Data can not be transferred or stored to the application "
41+
"because of the present device state"),
42+
0x08000023: ("Object dictionary dynamic generation fails or no object "
43+
"dictionary is present"),
4844
0x08000024: "No data available",
4945
}
5046

51-
def __init__(self, code: int):
47+
def __init__(self, code: Union[int, str]):
5248
#: Abort code
49+
if isinstance(code, str):
50+
try:
51+
self.code = self.from_string(code)
52+
except ValueError as e:
53+
raise ValueError(f"Unknown SDO abort description: {code}") from e
54+
else:
5355
self.code = code
5456

5557
def __str__(self):
@@ -62,8 +64,7 @@ def __eq__(self, other):
6264
"""Compare two exception objects based on SDO abort code."""
6365
return self.code == other.code
6466

65-
@staticmethod
66-
def from_string(text):
67+
def from_string(self, text):
6768
code = list(SdoAbortedError.CODES.keys())[
6869
list(SdoAbortedError.CODES.values()).index(text)
6970
]

canopen/sdo/server.py

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010

1111
class SdoBlockException(SdoAbortedError):
12-
def __init__(self, code: int):
13-
super.__init__(self, code)
12+
""" Dedicated SDO Block exception. """
1413

1514
class SdoServer(SdoBase):
1615
"""Creates an SDO server."""
@@ -68,6 +67,14 @@ def on_request(self, can_id, data, timestamp):
6867
logger.exception(exc)
6968

7069
def process_block(self, request):
70+
"""
71+
Process a block request, using a state mechanisme from SdoBlock class
72+
to handle the different states of the block transfer.
73+
74+
:param request:
75+
CAN message containing EMCY or SDO request.
76+
"""
77+
7178
logger.debug('process_block')
7279
command, _, _, code = SDO_ABORT_STRUCT.unpack_from(request)
7380
if command == 0x80:
@@ -84,14 +91,12 @@ def process_block(self, request):
8491
logger.debug('BLOCK_STATE_UP_INIT_RESP')
8592
#init response was sent, client required to send new request
8693
if (command & REQUEST_BLOCK_UPLOAD) != REQUEST_BLOCK_UPLOAD:
87-
raise SdoBlockException(0x05040001)
94+
raise SdoBlockException("Unknown SDO command specified")
8895
if (command & START_BLOCK_UPLOAD) != START_BLOCK_UPLOAD:
89-
raise SdoBlockException(0x05040001)
90-
# self.sdo_block.update_state(BLOCK_STATE_UP_DATA)
96+
raise SdoBlockException("Unknown SDO command specified")
9197

9298
# now start blasting data to client from server
9399
self.sdo_block.update_state(BLOCK_STATE_UP_DATA)
94-
#self.data_succesfull_upload = self.data_uploaded
95100

96101
blocks = self.sdo_block.get_upload_blocks()
97102
for block in blocks:
@@ -101,13 +106,12 @@ def process_block(self, request):
101106
logger.debug('BLOCK_STATE_UP_DATA')
102107
command, ackseq, newblk = SDO_BLOCKACK_STRUCT.unpack_from(request)
103108
if (command & REQUEST_BLOCK_UPLOAD) != REQUEST_BLOCK_UPLOAD:
104-
raise SdoBlockException(0x05040001)
109+
raise SdoBlockException("Unknown SDO command specified")
105110
elif (command & BLOCK_TRANSFER_RESPONSE) != BLOCK_TRANSFER_RESPONSE:
106-
raise SdoBlockException(0x05040001)
111+
raise SdoBlockException("Unknown SDO command specified")
107112
elif (ackseq != self.sdo_block.last_seqno):
108113
self.sdo_block.data_uploaded = self.sdo_block.data_succesfull_upload
109114

110-
111115
if self.sdo_block.size == self.sdo_block.data_uploaded:
112116
logger.debug('BLOCK_STATE_UP_DATA last data')
113117
self.sdo_block.update_state(BLOCK_STATE_UP_END)
@@ -131,12 +135,12 @@ def process_block(self, request):
131135
self.sdo_block = None
132136

133137
elif BLOCK_STATE_DOWNLOAD < self.sdo_block.state:
134-
logger.debug('BLOCK_STATE_DOWNLOAD')
135138
# in download state
136-
pass
139+
logger.debug('BLOCK_STATE_DOWNLOAD')
137140
else:
138141
# in neither
139-
raise SdoBlockException(0x08000022)
142+
raise SdoBlockException("Data can not be transferred or stored to the application "
143+
"because of the present device state")
140144

141145
def init_upload(self, request):
142146
_, index, subindex = SDO_STRUCT.unpack_from(request)
@@ -188,6 +192,13 @@ def segmented_upload(self, command):
188192
self.send_response(response)
189193

190194
def block_upload(self, request):
195+
"""
196+
Process an initial block upload request.
197+
Create a CAN response message and update the state of the SDO block.
198+
199+
:param request:
200+
CAN message containing SDO request.
201+
"""
191202
logging.debug('Enter server block upload')
192203
self.sdo_block = SdoBlock(self._node, request)
193204

@@ -314,6 +325,10 @@ def download(
314325
return self._node.set_data(index, subindex, data)
315326

316327
class SdoBlock():
328+
"""
329+
SdoBlock class to handle block transfer. It keeps track of the
330+
current state and the prepares data to be transferred.
331+
"""
317332
state = BLOCK_STATE_NONE
318333
crc = False
319334
data_uploaded = 0
@@ -323,41 +338,57 @@ class SdoBlock():
323338
last_seqno = 0
324339

325340
def __init__(self, node, request, docrc=False):
326-
341+
"""
342+
:param node:
343+
Node object owning the server
344+
:param request:
345+
CAN message containing SDO request.
346+
:param docrc:
347+
If True, CRC is calculated and checked.
348+
"""
327349
command, index, subindex = SDO_STRUCT.unpack_from(request)
328350
# only do crc if crccheck lib is available _and_ if requested
329351
_req_crc = (command & CRC_SUPPORTED) == CRC_SUPPORTED
330352

331353
if (command & SUB_COMMAND_MASK) == INITIATE_BLOCK_TRANSFER:
332354
self.state = BLOCK_STATE_INIT
333355
else:
334-
raise SdoBlockException(SdoAbortedError.from_string("Unknown SDO command specified"))
356+
raise SdoBlockException("Unknown SDO command specified")
335357

358+
# TODO: CRC of data if requested
336359
self.crc = CRC_SUPPORTED if (docrc & _req_crc) else 0
337360
self._node = node
338361
self.index = index
339362
self.subindex = subindex
340363
self.req_blocksize = request[4]
341364
self.seqno = 0
342365
if not 1 <= self.req_blocksize <= 127:
343-
raise SdoBlockException(SdoAbortedError.from_string("Invalid block size"))
366+
raise SdoBlockException("Invalid block size")
344367

345368
self.data = self._node.get_data(index,
346369
subindex,
347370
check_readable=True)
348371
self.size = len(self.data)
349372

350-
# TODO: add PST if needed
351-
# self.pst = data[5]
352-
353373
def update_state(self, new_state):
374+
"""
375+
Update the state of the SDO block transfer. The state is
376+
updated only if the new state is higher than the current
377+
state. Otherwise an exception is raised.
378+
"""
354379
logging.debug('update_state %X -> %X', self.state, new_state)
355380
if new_state >= self.state:
356381
self.state = new_state
357382
else:
358-
raise SdoBlockException(0x08000022)
383+
raise SdoBlockException("Data can not be transferred or stored to the application "
384+
"because of the present device state")
359385

360386
def get_upload_blocks(self):
387+
"""
388+
Get the blocks of data to be sent to the client. The blocks are
389+
created in a messages list of bytearrays.
390+
"""
391+
361392
msgs = []
362393

363394
# seq no 1 - 127, not 0 -..
@@ -387,6 +418,7 @@ def get_upload_blocks(self):
387418
return msgs
388419

389420
def get_data_byte(self):
421+
"""Get the next byte of data to be sent to the client."""
390422
if self.data_uploaded < self.size:
391423
self.data_uploaded += 1
392424
return self.data[self.data_uploaded-1]

0 commit comments

Comments
 (0)