Skip to content

Commit 60255bd

Browse files
committed
Fix _retransmit to reset _done; add block download retransmit test
1 parent 5715eca commit 60255bd

2 files changed

Lines changed: 27 additions & 46 deletions

File tree

canopen/sdo/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,8 @@ def _retransmit(self, ackseq, blksize):
788788
# Reset _seqno and update blksize
789789
self._seqno = 0
790790
self._blksize = blksize
791+
# Reset _done so the last segment can be re-sent
792+
self._done = False
791793
# We are retransmitting
792794
self._retransmitting = True
793795
# Resend the block

test/test_sdo.py

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,31 @@ def test_block_download(self):
193193
):
194194
fp.write(data)
195195

196+
def test_block_download_retransmit(self):
197+
"""Server acknowledges only 3 of 5 sequences; client must retransmit the rest."""
198+
self.data = [
199+
(TX, b'\xc6\x00\x20\x00\x23\x00\x00\x00'), # init block download, size=35, CRC
200+
(RX, b'\xa4\x00\x20\x00\x05\x00\x00\x00'), # server init resp, blksize=5, CRC
201+
(TX, b'\x01\x41\x42\x43\x44\x45\x46\x47'), # seq 1: ABCDEFG
202+
(TX, b'\x02\x48\x49\x4a\x4b\x4c\x4d\x4e'), # seq 2: HIJKLMN
203+
(TX, b'\x03\x4f\x50\x51\x52\x53\x54\x55'), # seq 3: OPQRSTU
204+
(TX, b'\x04\x56\x57\x58\x59\x5a\x31\x32'), # seq 4: VWXYZ12
205+
(TX, b'\x85\x33\x34\x35\x36\x37\x38\x39'), # seq 5 (NO_MORE_BLOCKS): 3456789
206+
(RX, b'\xa2\x03\x05\x00\x00\x00\x00\x00'), # ack: only 3 received, blksize=5
207+
(TX, b'\x01\x56\x57\x58\x59\x5a\x31\x32'), # retransmit seq 1: VWXYZ12
208+
(TX, b'\x82\x33\x34\x35\x36\x37\x38\x39'), # retransmit seq 2 (NO_MORE_BLOCKS): 3456789
209+
(RX, b'\xa2\x02\x05\x00\x00\x00\x00\x00'), # ack: all 2 received, blksize=5
210+
(TX, b'\xc1\x80\x00\x00\x00\x00\x00\x00'), # end block transfer, CRC=0x0080
211+
(RX, b'\xa1\x00\x00\x00\x00\x00\x00\x00'), # server confirms end
212+
]
213+
data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'
214+
with (
215+
self.network[2]
216+
.sdo["Writable string"]
217+
.open('wb', size=len(data), block_transfer=True) as fp
218+
):
219+
fp.write(data)
220+
196221
def test_segmented_download_zero_length(self):
197222
self.data = [
198223
(TX, b'\x21\x00\x20\x00\x00\x00\x00\x00'),
@@ -220,7 +245,6 @@ def test_block_upload(self):
220245
data = fp.read()
221246
self.assertEqual(data, 'Tiny Node - Mega Domains !')
222247

223-
224248
def test_sdo_block_upload_retransmit(self):
225249
"""Trigger a retransmit by only validating a block partially."""
226250
self.data = [
@@ -948,50 +972,5 @@ def test_init_from_unknown_string(self):
948972
canopen.SdoAbortedError("This description does not exist")
949973

950974

951-
class TestSdoAbortedError(unittest.TestCase):
952-
"""Unit tests for SdoAbortedError construction and helpers."""
953-
954-
def test_init_with_int_code(self):
955-
for code in canopen.SdoAbortedError.CODES:
956-
exc = canopen.SdoAbortedError(code)
957-
self.assertEqual(exc.code, code)
958-
959-
def test_str_known_code(self):
960-
for code, description in canopen.SdoAbortedError.CODES.items():
961-
exc = canopen.SdoAbortedError(code)
962-
self.assertIn(description, str(exc))
963-
964-
def test_str_unknown_code(self):
965-
exc = canopen.SdoAbortedError(0xDEADBEEF)
966-
self.assertIn("0xDEADBEEF", str(exc))
967-
968-
def test_eq(self):
969-
for code, description in canopen.SdoAbortedError.CODES.items():
970-
# Test equality with another instance of the same code, and with the code and description directly
971-
self.assertEqual(canopen.SdoAbortedError(code),
972-
canopen.SdoAbortedError(description))
973-
self.assertEqual(canopen.SdoAbortedError(code),
974-
code)
975-
self.assertEqual(canopen.SdoAbortedError(code),
976-
description)
977-
978-
self.assertNotEqual(canopen.SdoAbortedError(0x06090011),
979-
canopen.SdoAbortedError(0x08000000))
980-
981-
self.assertNotEqual(canopen.SdoAbortedError(0x06090011), "Value range of parameter exceeded")
982-
983-
with self.assertRaises(TypeError):
984-
canopen.SdoAbortedError(code) == 0.5 # Unsupported type for comparison
985-
986-
def test_init_from_string(self):
987-
for code, description in canopen.SdoAbortedError.CODES.items():
988-
exc = canopen.SdoAbortedError(description)
989-
self.assertEqual(exc.code, code)
990-
991-
def test_init_from_unknown_string(self):
992-
with self.assertRaises(ValueError):
993-
canopen.SdoAbortedError("This description does not exist")
994-
995-
996975
if __name__ == "__main__":
997976
unittest.main()

0 commit comments

Comments
 (0)