Skip to content

pdo: Write the entries of an ARRAY mapping in PdoMap.save() - #679

Open
0x-pankaj wants to merge 1 commit into
canopen-python:masterfrom
0x-pankaj:fix-pdo-save-array-mapping
Open

0x-pankaj wants to merge 1 commit into
canopen-python:masterfrom
0x-pankaj:fix-pdo-save-array-mapping

Conversation

@0x-pankaj

Copy link
Copy Markdown

When a PDO mapping parameter (0x1600–0x17FF / 0x1A00–0x1BFF) is declared as an ARRAY in the object dictionary (EDS ObjectType=0x8), PdoMap.save() writes the entry count but none of the mapping entries. The device ends up with sub-index 0 = N and its old (or zero) entries, so the PDO carries the wrong data without any error. Mappings declared as a RECORD are not affected.

Cause

save() follows the CiA 301 procedure and first sets sub-index 0 to 0, then writes the entries with:

for var, entry in zip(self.map, self.map_array.values()):

For an ARRAY, self.map_array is an SdoArray, whose __len__ is self[0].raw: it uploads sub-index 0 from the device. That value was just set to 0, so values() yields nothing, no entry is written, and then sub-index 0 is set to len(self.map).

Fix

Address the entries by the sub-indices the object dictionary defines instead of iterating the SdoArray:

entries = (
    self.map_array[subindex] for subindex in self.map_array.od if subindex != 0
)
for var, entry in zip(self.map, entries):

RECORD mappings and the fixed-count workaround (_fill_map pads self.map to the device's count) behave as before, and it still stops at the entries the dictionary defines.

Tests

test_pdo_save_writes_the_entries_of_an_array_mapping builds a LocalNode whose TPDO 1 mapping is an ODArray, saves a two-entry map (one with a 4-bit length) and uploads the entries back. It fails before the change (entry 1 reads back 0x00000000) and passes after. The full suite passes (281 passed, 1 skipped), and the change adds no ruff findings.

I also checked it with a randomized round trip (save a mapping, read it back with a fresh PdoMap.read()): before the change the mapping was lost in 235 of 300 configurations; after it, all 300 round-trip correctly, including custom bit lengths, dummy entries, RTR and timer settings.

save() sets sub-index 0 of the mapping to 0 and then iterates
self.map_array.values() to write the entries. For a mapping declared as an
ARRAY, map_array is an SdoArray whose length is uploaded from sub-index 0,
which was just set to 0, so no entry is written and only the count is.

Address the entries by the sub-indices the object dictionary defines
instead. RECORD mappings and the fixed-count workaround behave as before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant