From 60f064e55ab36142eac503456a9a894ac98bec9c Mon Sep 17 00:00:00 2001 From: Sudlav <101553227+Sudlav@users.noreply.github.com> Date: Wed, 16 Mar 2022 21:56:47 +0100 Subject: [PATCH 01/11] Corrected casing of BaudRate_xx keywords in DeviceInfo section of EDS files (#303) Co-authored-by: Andreas Valdusson --- canopen/objectdictionary/eds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/canopen/objectdictionary/eds.py b/canopen/objectdictionary/eds.py index afd94159..de4db99d 100644 --- a/canopen/objectdictionary/eds.py +++ b/canopen/objectdictionary/eds.py @@ -52,7 +52,7 @@ def import_eds(source, node_id): else: for rate in [10, 20, 50, 125, 250, 500, 800, 1000]: baudPossible = int( - eds.get("DeviceInfo", "Baudrate_%i" % rate, fallback='0'), 0) + eds.get("DeviceInfo", "BaudRate_%i" % rate, fallback='0'), 0) if baudPossible != 0: od.device_information.allowed_baudrates.add(rate*1000) @@ -407,7 +407,7 @@ def export_record(var, eds): for rate in od.device_information.allowed_baudrates.union( {10e3, 20e3, 50e3, 125e3, 250e3, 500e3, 800e3, 1000e3}): eds.set( - "DeviceInfo", "Baudrate_%i" % (rate/1000), + "DeviceInfo", "BaudRate_%i" % (rate/1000), int(rate in od.device_information.allowed_baudrates)) if device_commisioning and (od.bitrate or od.node_id): From 3d57a1c817d06634fcb57818fc7b5d5441908a99 Mon Sep 17 00:00:00 2001 From: Sudlav <101553227+Sudlav@users.noreply.github.com> Date: Fri, 18 Mar 2022 01:04:33 +0100 Subject: [PATCH 02/11] Making sure the FileInfo section is copied from the imported EDS to the exported EDS (#304) Co-authored-by: Andreas Valdusson --- canopen/objectdictionary/eds.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/canopen/objectdictionary/eds.py b/canopen/objectdictionary/eds.py index de4db99d..0d0ffb7e 100644 --- a/canopen/objectdictionary/eds.py +++ b/canopen/objectdictionary/eds.py @@ -369,10 +369,10 @@ def export_record(var, eds): "EdsVersion": 4.2, } - file_info.setdefault("ModificationDate", defmtime.strftime("%m-%d-%Y")) - file_info.setdefault("ModificationTime", defmtime.strftime("%I:%m%p")) - for k, v in origFileInfo.items(): - file_info.setdefault(k, v) + file_info.setdefault("ModificationDate", defmtime.strftime("%m-%d-%Y")) + file_info.setdefault("ModificationTime", defmtime.strftime("%I:%m%p")) + for k, v in origFileInfo.items(): + file_info.setdefault(k, v) eds.add_section("FileInfo") for k, v in file_info.items(): From 074cbbc4d4c2c7803dc1e0151f6f534dbe44efc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Filipe=20Silva?= Date: Fri, 18 Mar 2022 00:07:54 +0000 Subject: [PATCH 03/11] change missing Baudrate to BaudRate Following the changes done #304, #305 --- canopen/objectdictionary/eds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/canopen/objectdictionary/eds.py b/canopen/objectdictionary/eds.py index 0d0ffb7e..872df234 100644 --- a/canopen/objectdictionary/eds.py +++ b/canopen/objectdictionary/eds.py @@ -85,7 +85,7 @@ def import_eds(source, node_id): pass if eds.has_section("DeviceComissioning"): - od.bitrate = int(eds.get("DeviceComissioning", "Baudrate")) * 1000 + od.bitrate = int(eds.get("DeviceComissioning", "BaudRate")) * 1000 od.node_id = int(eds.get("DeviceComissioning", "NodeID"), 0) for section in eds.sections(): @@ -413,7 +413,7 @@ def export_record(var, eds): if device_commisioning and (od.bitrate or od.node_id): eds.add_section("DeviceComissioning") if od.bitrate: - eds.set("DeviceComissioning", "Baudrate", int(od.bitrate / 1000)) + eds.set("DeviceComissioning", "BaudRate", int(od.bitrate / 1000)) if od.node_id: eds.set("DeviceComissioning", "NodeID", int(od.node_id)) From b3f67c1243d61a6816ae1f955ae3679306d85819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 18 Mar 2022 00:34:53 +0000 Subject: [PATCH 04/11] fix: change Baudrate to BaudRate missing on .eds files the missing change on sample.eds was preventing the tests from running --- examples/eds/e35.eds | 20 ++++++++++---------- test/sample.eds | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/eds/e35.eds b/examples/eds/e35.eds index 4978b818..bf0baff0 100644 --- a/examples/eds/e35.eds +++ b/examples/eds/e35.eds @@ -18,14 +18,14 @@ ProductName=example ProductNumber=25 RevisionNumber=295 OrderCode=25 -Baudrate_10=1 -Baudrate_20=1 -Baudrate_50=1 -Baudrate_125=1 -Baudrate_250=1 -Baudrate_500=1 -Baudrate_800=0 -Baudrate_1000=1 +BaudRate_10=1 +BaudRate_20=1 +BaudRate_50=1 +BaudRate_125=1 +BaudRate_250=1 +BaudRate_500=1 +BaudRate_800=0 +BaudRate_1000=1 SimpleBootUpMaster=0 SimpleBootUpSlave=1 Granularity=8 @@ -243,7 +243,7 @@ HighLimit=0x7F ParameterValue=0x20 [2000sub2] -ParameterName=Baudrate +ParameterName=BaudRate ObjectType=0x7 DataType=0x0005 AccessType=rw @@ -324,7 +324,7 @@ LowLimit=0x1 HighLimit=0x7F [2001sub2] -ParameterName=Baudrate +ParameterName=BaudRate ObjectType=0x7 DataType=0x0005 AccessType=rw diff --git a/test/sample.eds b/test/sample.eds index b01a9ee5..bea6b9c3 100644 --- a/test/sample.eds +++ b/test/sample.eds @@ -32,7 +32,7 @@ LSS_Supported=0 [DeviceComissioning] NodeID=2 NodeName=Some name -Baudrate=500 +BaudRate=500 NetNumber=0 LSS_SerialNumber=0 From 33908247b1020975784062558e2e0174f4f7a52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Filipe=20Silva?= Date: Thu, 28 Apr 2022 15:37:59 +0100 Subject: [PATCH 05/11] fix eds file example with valid VendorNumber #313 `ValueError: invalid literal for int() with base 0: '001'` The error happens while trying to parse DeviceInfo >> VendorNumber with leading zeros --- examples/eds/e35.eds | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/eds/e35.eds b/examples/eds/e35.eds index bf0baff0..17b24879 100644 --- a/examples/eds/e35.eds +++ b/examples/eds/e35.eds @@ -13,7 +13,7 @@ ModifiedBy=Manufacturer [DeviceInfo] VendorName=Manufacturer -VendorNumber=001 +VendorNumber=101 ProductName=example ProductNumber=25 RevisionNumber=295 From c7ad0a822a20a765f0fc7c43be0f4450b7a536ef Mon Sep 17 00:00:00 2001 From: Clark Willison Date: Mon, 23 May 2022 06:10:07 -0700 Subject: [PATCH 06/11] network: fix broken link to python-can readthedocs in docstring (#319) --- canopen/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canopen/network.py b/canopen/network.py index 04acda18..00c21cf0 100644 --- a/canopen/network.py +++ b/canopen/network.py @@ -94,7 +94,7 @@ def connect(self, *args, **kwargs) -> "Network": Backend specific channel for the CAN interface. :param str bustype: Name of the interface. See - `python-can manual `__ + `python-can manual `__ for full list of supported interfaces. :param int bitrate: Bitrate in bit/s. From e3829fc4f0fe1fb0193c1f40ac2544195c942393 Mon Sep 17 00:00:00 2001 From: Samuel Lee <54152208+samsamfire@users.noreply.github.com> Date: Mon, 8 Aug 2022 21:34:28 +0200 Subject: [PATCH 07/11] Adding retransmit functionnality to sdo block download (#324) --- canopen/sdo/client.py | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/canopen/sdo/client.py b/canopen/sdo/client.py index 0ed083e4..7e0f58bf 100644 --- a/canopen/sdo/client.py +++ b/canopen/sdo/client.py @@ -628,6 +628,8 @@ def __init__(self, sdo_client, index, subindex=0, size=None, request_crc_support self._seqno = 0 self._crc = sdo_client.crc_cls() self._last_bytes_sent = 0 + self._current_block = [] + self._retransmitting = False command = REQUEST_BLOCK_DOWNLOAD | INITIATE_BLOCK_TRANSFER if request_crc_support: command |= CRC_SUPPORTED @@ -708,7 +710,10 @@ def send(self, b, end=False): request[1:len(b) + 1] = b self.sdo_client.send_request(request) self.pos += len(b) - if self.crc_supported: + # Add the sent data to the current block buffer + self._current_block.append(b) + # Don't calculate crc if retransmitting + if self.crc_supported and not self._retransmitting: # Calculate CRC self._crc.process(b) if self._seqno >= self._blksize: @@ -731,14 +736,37 @@ def _block_ack(self): raise SdoCommunicationError("Server did not respond with a " "block download response") if ackseq != self._blksize: - self.sdo_client.abort(0x05040003) - raise SdoCommunicationError( - ("%d of %d sequences were received. " - "Retransmission is not supported yet.") % (ackseq, self._blksize)) + # Sequence error, try to retransmit + self._retransmit(ackseq, blksize) + # We should be back in sync + return + # Clear the current block buffer + self._current_block = [] logger.debug("All %d sequences were received successfully", ackseq) logger.debug("Server requested a block size of %d", blksize) self._blksize = blksize self._seqno = 0 + + def _retransmit(self, ackseq, blksize): + """Retransmit the failed block""" + logger.info(("%d of %d sequences were received. " + "Will start retransmission") % (ackseq, self._blksize)) + # Sub blocks betwen ackseq and end of corrupted block need to be resent + # Get the part of the block to resend + block = self._current_block[ackseq:] + # Go back to correct position in stream + self.pos = self.pos - (len(block) * 7) + # Reset the _current_block before starting the retransmission + self._current_block = [] + # Reset _seqno and update blksize + self._seqno = 0 + self._blksize = blksize + # We are retransmitting + self._retransmitting = True + # Resend the block + for b in block: + self.write(b) + self._retransmitting = False def close(self): """Closes the stream.""" From 62eb145920146386c3e0d024f7ddad52fdb18f97 Mon Sep 17 00:00:00 2001 From: Mark Truttmann <50853333+mtru32@users.noreply.github.com> Date: Mon, 24 Oct 2022 19:30:16 -0500 Subject: [PATCH 08/11] Fix Typo (#332) Assuming this should be through instead of trough --- canopen/node/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canopen/node/remote.py b/canopen/node/remote.py index 864ffeb3..5aca17ff 100644 --- a/canopen/node/remote.py +++ b/canopen/node/remote.py @@ -24,7 +24,7 @@ class RemoteNode(BaseNode): Object dictionary as either a path to a file, an ``ObjectDictionary`` or a file like object. :param load_od: - Enable the Object Dictionary to be sent trough SDO's to the remote + Enable the Object Dictionary to be sent through SDO's to the remote node at startup. """ From 559274fe5eecd8564c3a49330c21f9583fcdcaac Mon Sep 17 00:00:00 2001 From: Mihail Emelyanov Date: Sat, 19 Nov 2022 02:18:35 +0500 Subject: [PATCH 09/11] Fix typo (#334) --- canopen/lss.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/canopen/lss.py b/canopen/lss.py index d77f528f..d375e852 100644 --- a/canopen/lss.py +++ b/canopen/lss.py @@ -248,7 +248,7 @@ def fast_scan(self): :return: True if a slave is found. False if there is no candidate. - list is the LSS identities [vendor_id, product_code, revision_number, seerial_number] + list is the LSS identities [vendor_id, product_code, revision_number, serial_number] :rtype: bool, list """ lss_id = [0] * 4 @@ -265,21 +265,21 @@ def fast_scan(self): if not self.__send_fast_scan_message(lss_id[lss_sub], lss_bit_check, lss_sub, lss_next): lss_id[lss_sub] |= 1< Date: Sun, 11 Dec 2022 19:41:45 +0100 Subject: [PATCH 10/11] Check data length sdo server (#338) --- canopen/node/local.py | 6 ++++++ test/test_local.py | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/canopen/node/local.py b/canopen/node/local.py index ecce2dff..9e0a80b3 100644 --- a/canopen/node/local.py +++ b/canopen/node/local.py @@ -100,6 +100,12 @@ def set_data( if check_writable and not obj.writable: raise SdoAbortedError(0x06010002) + # Check length matches type (length of od variable is in bits) + if obj.data_type in objectdictionary.NUMBER_TYPES and ( + not 8 * len(data) == len(obj) + ): + raise SdoAbortedError(0x06070010) + # Try callbacks for callback in self._write_callbacks: callback(index=index, subindex=subindex, od=obj, data=data) diff --git a/test/test_local.py b/test/test_local.py index aed3a28c..f4119d44 100644 --- a/test/test_local.py +++ b/test/test_local.py @@ -71,6 +71,16 @@ def test_expedited_download(self): value = self.local_node.sdo[0x2004].raw self.assertEqual(value, 0xfeff) + def test_expedited_download_wrong_datatype(self): + # Try to write 32 bit in integer16 type + with self.assertRaises(canopen.SdoAbortedError) as error: + self.remote_node.sdo.download(0x2001, 0x0, bytes([10, 10, 10, 10])) + self.assertEqual(error.exception.code, 0x06070010) + # Try to write normal 16 bit word, should be ok + self.remote_node.sdo.download(0x2001, 0x0, bytes([10, 10])) + value = self.remote_node.sdo.upload(0x2001, 0x0) + self.assertEqual(value, bytes([10, 10])) + def test_segmented_download(self): self.remote_node.sdo[0x2000].raw = "Another cool device" value = self.local_node.sdo[0x2000].data From a59cc243d4947df487aeba739ff6ae2e280cf033 Mon Sep 17 00:00:00 2001 From: Christian Sandberg Date: Tue, 3 Jan 2023 15:18:48 +0100 Subject: [PATCH 11/11] Remove testing of older Python versions --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 3efb3261..2962fc69 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, '3.x'] + python-version: ['3.x'] steps: - uses: actions/checkout@v2