From 6bc9305300fb4696a7e4bcdecb67cdbf64fe4612 Mon Sep 17 00:00:00 2001 From: Federico Spada Date: Sun, 21 Sep 2025 17:01:43 +0200 Subject: [PATCH] Custom Options for EDS file Allowed to Read/Write options not defined by the EDS Standard. --- canopen/objectdictionary/__init__.py | 6 ++++++ canopen/objectdictionary/eds.py | 31 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/canopen/objectdictionary/__init__.py b/canopen/objectdictionary/__init__.py index fa694c56..8eb057f5 100644 --- a/canopen/objectdictionary/__init__.py +++ b/canopen/objectdictionary/__init__.py @@ -209,6 +209,8 @@ def __init__(self, name: str, index: int): self.storage_location = None self.subindices = {} self.names = {} + #: Key-Value pairs not defined by the standard + self.custom_options = {} def __repr__(self) -> str: return f"<{type(self).__qualname__} {self.name!r} at {pretty_index(self.index)}>" @@ -268,6 +270,8 @@ def __init__(self, name: str, index: int): self.storage_location = None self.subindices = {} self.names = {} + #: Key-Value pairs not defined by the standard + self.custom_options = {} def __repr__(self) -> str: return f"<{type(self).__qualname__} {self.name!r} at {pretty_index(self.index)}>" @@ -374,6 +378,8 @@ def __init__(self, name: str, index: int, subindex: int = 0): self.storage_location = None #: Can this variable be mapped to a PDO self.pdo_mappable = False + #: Key-Value pairs not defined by the standard + self.custom_options = {} def __repr__(self) -> str: subindex = self.subindex if isinstance(self.parent, (ODRecord, ODArray)) else None diff --git a/canopen/objectdictionary/eds.py b/canopen/objectdictionary/eds.py index 8ab1a349..c13b90df 100644 --- a/canopen/objectdictionary/eds.py +++ b/canopen/objectdictionary/eds.py @@ -131,6 +131,7 @@ def import_eds(source, node_id): if object_type in (VAR, DOMAIN): var = build_variable(eds, section, node_id, index) + var.custom_options = _get_custom_options(eds, section) od.add_object(var) elif object_type == ARR and eds.has_option(section, "CompactSubObj"): arr = objectdictionary.ODArray(name, index) @@ -140,14 +141,17 @@ def import_eds(source, node_id): arr.add_member(last_subindex) arr.add_member(build_variable(eds, section, node_id, index, 1)) arr.storage_location = storage_location + arr.custom_options = _get_custom_options(eds, section) od.add_object(arr) elif object_type == ARR: arr = objectdictionary.ODArray(name, index) arr.storage_location = storage_location + arr.custom_options = _get_custom_options(eds, section) od.add_object(arr) elif object_type == RECORD: record = objectdictionary.ODRecord(name, index) record.storage_location = storage_location + record.custom_options = _get_custom_options(eds, section) od.add_object(record) continue @@ -253,6 +257,18 @@ def _revert_variable(var_type, value): else: return f"0x{value:02X}" +_STANDARD_OPTIONS = ["ObjectType" , "ParameterName" , "DataType" , "AccessType" , + "PDOMapping" , "LowLimit" , "HighLimit" , "DefaultValue" , + "ParameterValue" , "Factor" , "Description" , "Unit" , + "StorageLocation" , "CompactSubObj" ] + +def _get_custom_options(eds, section): + custom_options = {} + for option, value in eds.items(section): + if option not in _STANDARD_OPTIONS: + custom_options[option] = value + return custom_options + def build_variable(eds, section, node_id, index, subindex=0): """Creates a object dictionary entry. @@ -332,6 +348,8 @@ def build_variable(eds, section, node_id, index, subindex=0): var.unit = eds.get(section, "Unit") except ValueError: pass + + var.custom_options = _get_custom_options(eds, section) return var @@ -406,12 +424,17 @@ def export_variable(var, eds): if getattr(var, 'unit', '') != '': eds.set(section, "Unit", var.unit) + for option, value in var.custom_options.items(): + eds.set(section, option, value) + def export_record(var, eds): section = f"{var.index:04X}" export_common(var, eds, section) eds.set(section, "SubNumber", f"0x{len(var.subindices):X}") ot = RECORD if isinstance(var, objectdictionary.ODRecord) else ARR eds.set(section, "ObjectType", f"0x{ot:X}") + for option, value in var.custom_options.items(): + eds.set(section, option, value) for i in var: export_variable(var[i], eds) @@ -498,19 +521,19 @@ def export_record(var, eds): def mandatory_indices(x): return x in {0x1000, 0x1001, 0x1018} - def manufacturer_idices(x): - return x in range(0x2000, 0x6000) + def manufacturer_indices(x): + return 0x2000 <= x < 0x6000 def optional_indices(x): return all(( x > 0x1001, not mandatory_indices(x), - not manufacturer_idices(x), + not manufacturer_indices(x), )) supported_mantatory_indices = list(filter(mandatory_indices, od)) supported_optional_indices = list(filter(optional_indices, od)) - supported_manufacturer_indices = list(filter(manufacturer_idices, od)) + supported_manufacturer_indices = list(filter(manufacturer_indices, od)) def add_list(section, list): eds.add_section(section)