Skip to content

Commit 0130eb8

Browse files
acolombsamsamfire
andauthored
sdo.client: Add missing abort messages (#594)
SDO abort messages were sent in some cases when a response times out or has an unexpected server command specifier. But not consistently, thus the following cases are now added: Mismatched scs: ReadableStream, after upload segment request WritableStream, after download initiate request WritableStream, after expedited download request WritableStream, after download segment request Toggle bit mismatch (reports as not toggled): ReadableStream, after upload segment request * Consistently format abort code literals. * Fix typo (grammatical error in exception message). * Avoid duplicate SDO abort messages on timeout in _block_ack() and _end_upload(). * Add docstring to read_response() and detail exceptions. Co-authored-by: samsam <[email protected]>
1 parent 09f6e9e commit 0130eb8

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

canopen/sdo/client.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ def send_request(self, request):
6565
break
6666

6767
def read_response(self):
68+
"""Wait for an SDO response and handle timeout or remote abort.
69+
70+
:raises canopen.SdoAbortedError:
71+
When receiving an SDO abort response from the server.
72+
:raises canopen.SdoCommunicationError:
73+
After timeout with no response received.
74+
"""
6875
try:
6976
response = self.responses.get(
7077
block=True, timeout=self.RESPONSE_TIMEOUT)
@@ -89,11 +96,11 @@ def request_response(self, sdo_request):
8996
except SdoCommunicationError as e:
9097
retries_left -= 1
9198
if not retries_left:
92-
self.abort(0x5040000)
99+
self.abort(0x0504_0000)
93100
raise
94101
logger.warning(str(e))
95102

96-
def abort(self, abort_code=0x08000000):
103+
def abort(self, abort_code=0x0800_0000):
97104
"""Abort current transfer."""
98105
request = bytearray(8)
99106
request[0] = REQUEST_ABORTED
@@ -302,8 +309,10 @@ def read(self, size=-1):
302309
response = self.sdo_client.request_response(request)
303310
res_command, = struct.unpack_from("B", response)
304311
if res_command & 0xE0 != RESPONSE_SEGMENT_UPLOAD:
312+
self.sdo_client.abort(0x0504_0001)
305313
raise SdoCommunicationError(f"Unexpected response 0x{res_command:02X}")
306314
if res_command & TOGGLE_BIT != self._toggle:
315+
self.sdo_client.abort(0x0503_0000)
307316
raise SdoCommunicationError("Toggle bit mismatch")
308317
length = 7 - ((res_command >> 1) & 0x7)
309318
if res_command & NO_MORE_DATA:
@@ -362,6 +371,7 @@ def __init__(self, sdo_client, index, subindex=0, size=None, force_segment=False
362371
response = sdo_client.request_response(request)
363372
res_command, = struct.unpack_from("B", response)
364373
if res_command != RESPONSE_DOWNLOAD:
374+
self.sdo_client.abort(0x0504_0001)
365375
raise SdoCommunicationError(
366376
f"Unexpected response 0x{res_command:02X}")
367377
else:
@@ -390,6 +400,7 @@ def write(self, b):
390400
response = self.sdo_client.request_response(request)
391401
res_command, = struct.unpack_from("B", response)
392402
if res_command & 0xE0 != RESPONSE_DOWNLOAD:
403+
self.sdo_client.abort(0x0504_0001)
393404
raise SdoCommunicationError(
394405
f"Unexpected response 0x{res_command:02X}")
395406
bytes_sent = len(b)
@@ -414,6 +425,7 @@ def write(self, b):
414425
response = self.sdo_client.request_response(request)
415426
res_command, = struct.unpack("B", response[0:1])
416427
if res_command & 0xE0 != RESPONSE_SEGMENT_DOWNLOAD:
428+
self.sdo_client.abort(0x0504_0001)
417429
raise SdoCommunicationError(
418430
f"Unexpected response 0x{res_command:02X} "
419431
f"(expected 0x{RESPONSE_SEGMENT_DOWNLOAD:02X})")
@@ -487,7 +499,7 @@ def __init__(self, sdo_client, index, subindex=0, request_crc_support=True):
487499
res_command, res_index, res_subindex = SDO_STRUCT.unpack_from(response)
488500
if res_command & 0xE0 != RESPONSE_BLOCK_UPLOAD:
489501
self._error = True
490-
self.sdo_client.abort(0x05040001)
502+
self.sdo_client.abort(0x0504_0001)
491503
raise SdoCommunicationError(f"Unexpected response 0x{res_command:02X}")
492504
# Check that the message is for us
493505
if res_index != index or res_subindex != subindex:
@@ -544,7 +556,7 @@ def read(self, size=-1):
544556
if self._done:
545557
if self._server_crc != self._crc.final():
546558
self._error = True
547-
self.sdo_client.abort(0x05040004)
559+
self.sdo_client.abort(0x0504_0004)
548560
raise SdoCommunicationError("CRC is not OK")
549561
logger.info("CRC is OK")
550562
self.pos += len(data)
@@ -564,8 +576,8 @@ def _retransmit(self):
564576
self._ackseq = seqno
565577
return response
566578
self._error = True
567-
self.sdo_client.abort(0x05040000)
568-
raise SdoCommunicationError("Some data were lost and could not be retransmitted")
579+
self.sdo_client.abort(0x0504_0000)
580+
raise SdoCommunicationError("Some data was lost and could not be retransmitted")
569581

570582
def _ack_block(self):
571583
request = bytearray(8)
@@ -576,15 +588,19 @@ def _ack_block(self):
576588
self._ackseq = 0
577589

578590
def _end_upload(self):
579-
response = self.sdo_client.read_response()
591+
try:
592+
response = self.sdo_client.read_response()
593+
except SdoCommunicationError:
594+
self.abort(0x0504_0000)
595+
raise
580596
res_command, self._server_crc = struct.unpack_from("<BH", response)
581597
if res_command & 0xE0 != RESPONSE_BLOCK_UPLOAD:
582598
self._error = True
583-
self.sdo_client.abort(0x05040001)
599+
self.sdo_client.abort(0x0504_0001)
584600
raise SdoCommunicationError(f"Unexpected response 0x{res_command:02X}")
585601
if res_command & 0x3 != END_BLOCK_TRANSFER:
586602
self._error = True
587-
self.sdo_client.abort(0x05040001)
603+
self.sdo_client.abort(0x0504_0001)
588604
raise SdoCommunicationError("Server did not end transfer as expected")
589605
# Return number of bytes not used in last message
590606
return (res_command >> 2) & 0x7
@@ -654,7 +670,7 @@ def __init__(self, sdo_client, index, subindex=0, size=None, request_crc_support
654670
response = sdo_client.request_response(request)
655671
res_command, res_index, res_subindex = SDO_STRUCT.unpack_from(response)
656672
if res_command & 0xE0 != RESPONSE_BLOCK_DOWNLOAD:
657-
self.sdo_client.abort(0x05040001)
673+
self.sdo_client.abort(0x0504_0001)
658674
raise SdoCommunicationError(
659675
f"Unexpected response 0x{res_command:02X}")
660676
# Check that the message is for us
@@ -736,14 +752,18 @@ def tell(self):
736752

737753
def _block_ack(self):
738754
logger.debug("Waiting for acknowledgement of last block...")
739-
response = self.sdo_client.read_response()
755+
try:
756+
response = self.sdo_client.read_response()
757+
except SdoCommunicationError:
758+
self.sdo_client.abort(0x0504_0000)
759+
raise
740760
res_command, ackseq, blksize = struct.unpack_from("BBB", response)
741761
if res_command & 0xE0 != RESPONSE_BLOCK_DOWNLOAD:
742-
self.sdo_client.abort(0x05040001)
762+
self.sdo_client.abort(0x0504_0001)
743763
raise SdoCommunicationError(
744764
f"Unexpected response 0x{res_command:02X}")
745765
if res_command & 0x3 != BLOCK_TRANSFER_RESPONSE:
746-
self.sdo_client.abort(0x05040001)
766+
self.sdo_client.abort(0x0504_0001)
747767
raise SdoCommunicationError("Server did not respond with a "
748768
"block download response")
749769
if ackseq != self._blksize:

0 commit comments

Comments
 (0)