From 66d0bb286150498cc503f7466b2618b46c458f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Sun, 15 Jun 2025 18:09:53 +0200 Subject: [PATCH] Avoid truncating unknown types in SDO upload. When an OD entry is found in SdoClient.upload(), the truncation is currently skipped only for those types explicitly listed as variable length data (domain, strings). That causes unknown types to be truncated to whatever their length indicates, which is usually one byte. Invert the condition to check all types with an explicitly known size, a.k.a. those listed in STRUCT_TYPES where the required length can be deduced from the structure format. Re-enable the unit tests which were skipped based on the previously buggy behavior. --- canopen/objectdictionary/__init__.py | 6 ++++++ canopen/sdo/client.py | 4 +--- test/test_sdo.py | 2 -- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/canopen/objectdictionary/__init__.py b/canopen/objectdictionary/__init__.py index 09fe6e03..c67b3b4a 100644 --- a/canopen/objectdictionary/__init__.py +++ b/canopen/objectdictionary/__init__.py @@ -419,6 +419,12 @@ def add_bit_definition(self, name: str, bits: List[int]) -> None: """ self.bit_definitions[name] = bits + @property + def fixed_size(self) -> bool: + """Indicate whether the amount of needed data is known in advance.""" + # Only for types which we parse using a structure. + return self.data_type in self.STRUCT_TYPES + def decode_raw(self, data: bytes) -> Union[int, float, str, bytes, bytearray]: if self.data_type == VISIBLE_STRING: # Strip any trailing NUL characters from C-based systems diff --git a/canopen/sdo/client.py b/canopen/sdo/client.py index 6d92588e..fd5fd99b 100644 --- a/canopen/sdo/client.py +++ b/canopen/sdo/client.py @@ -126,9 +126,7 @@ def upload(self, index: int, subindex: int) -> bytes: var = self.od.get_variable(index, subindex) if var is not None: # Found a matching variable in OD - # If this is a data type (string, domain etc) the size is - # unknown anyway so keep the data as is - if var.data_type not in objectdictionary.DATA_TYPES: + if var.fixed_size: # Get the size in bytes for this variable var_size = len(var) // 8 if response_size is None or var_size < response_size: diff --git a/test/test_sdo.py b/test/test_sdo.py index fea52b6a..78012a30 100644 --- a/test/test_sdo.py +++ b/test/test_sdo.py @@ -814,7 +814,6 @@ def test_unknown_od_112(self): def test_unknown_datatype32(self): """Test an unknown datatype, but known OD, of 32 bits (4 bytes).""" - return # FIXME: Disabled temporarily until datatype conditionals are fixed, see #436 # Add fake entry 0x2100 to OD, using fake datatype 0xFF if 0x2100 not in self.node.object_dictionary: fake_var = ODVariable("Fake", 0x2100) @@ -829,7 +828,6 @@ def test_unknown_datatype32(self): def test_unknown_datatype112(self): """Test an unknown datatype, but known OD, of 112 bits (14 bytes).""" - return # FIXME: Disabled temporarily until datatype conditionals are fixed, see #436 # Add fake entry 0x2100 to OD, using fake datatype 0xFF if 0x2100 not in self.node.object_dictionary: fake_var = ODVariable("Fake", 0x2100)