From 36c8488febc20e1d351135c90dd8966ab1d07dfb Mon Sep 17 00:00:00 2001 From: meifonglow Date: Fri, 5 Jul 2024 06:45:12 +1000 Subject: [PATCH] Add support for loading DCF configuration to remote node (#427) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle PDO-related objects through the associated methods in the PdoBase class when initializing a RemoteNode from an ObjectDictionary with provided values (DCF file usually). This avoids the locally cached mapping information to get out of sync with the PDO configuration parameters, and thus eliminates the need to read back those same objects. The PdoBase.read() method must honor DCF-provided values for this purpose. It previously only respected the OD default values when called with from_od=True. Co-authored-by: André Colomb --- canopen/node/remote.py | 15 +++++++++++---- canopen/pdo/base.py | 13 +++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/canopen/node/remote.py b/canopen/node/remote.py index f3054391..4f3281db 100644 --- a/canopen/node/remote.py +++ b/canopen/node/remote.py @@ -146,16 +146,23 @@ def load_configuration(self) -> None: Iterate through all objects in the Object Dictionary and download the values to the remote node via SDO. - Then, to avoid PDO mapping conflicts, read back (upload) the PDO - configuration via SDO. + To avoid PDO mapping conflicts, PDO-related objects are handled through + the methods :meth:`canopen.pdo.PdoBase.read` and + :meth:`canopen.pdo.PdoBase.save`. - :see-also: :meth:`canopen.pdo.PdoBase.read` """ + # First apply PDO configuration from object dictionary + self.pdo.read(from_od=True) + self.pdo.save() + + # Now apply all other records in object dictionary for obj in self.object_dictionary.values(): + if 0x1400 <= obj.index < 0x1c00: + # Ignore PDO related objects + continue if isinstance(obj, ODRecord) or isinstance(obj, ODArray): for subobj in obj.values(): if isinstance(subobj, ODVariable) and subobj.writable and (subobj.value is not None): self.__load_configuration_helper(subobj.index, subobj.subindex, subobj.name, subobj.value) elif isinstance(obj, ODVariable) and obj.writable and (obj.value is not None): self.__load_configuration_helper(obj.index, None, obj.name, obj.value) - self.pdo.read() # reads the new configuration from the driver diff --git a/canopen/pdo/base.py b/canopen/pdo/base.py index d467cdb3..def74ff0 100644 --- a/canopen/pdo/base.py +++ b/canopen/pdo/base.py @@ -320,11 +320,20 @@ def add_callback(self, callback: Callable[[PdoMap], None]) -> None: self.callbacks.append(callback) def read(self, from_od=False) -> None: - """Read PDO configuration for this map using SDO.""" + """Read PDO configuration for this map. + + :param from_od: + Read using SDO if False, read from object dictionary if True. + When reading from object dictionary, if DCF populated a value, the + DCF value will be used, otherwise the EDS default will be used instead. + """ def _raw_from(param): if from_od: - return param.od.default + if param.od.value is not None: + return param.od.value + else: + return param.od.default return param.raw cob_id = _raw_from(self.com_record[1])