Skip to content

Commit fc577d1

Browse files
pdo: Skip saving if no COB-ID was set (fixes #445) (#446)
The PdoBase.save() method would fail with a cryptic TypeError exception when the COB-ID was not previously set (still at None). Instead just skip the corresponding PDO and log an INFO level message about it. Add logging when re-enabling the PDO as well. Also fix some minor issues in surrounding code: * Added a test for PDO saving from EDS without further settings. * Skip the always true condition "self.map is not None". The attribute is initialized as an empty list. * Simplify check for curtis_hack using getattr(). * Remove unnecessary initialization in PdoMap.__getitem__(). * Removed unused variable "data" in PdoVariable.set_data() * Wrong type for empty argument to send_message(). Co-authored-by: Frieder Schüler <frieder.schueler@bizerba.com>
1 parent 5367d83 commit fc577d1

File tree

2 files changed

+49
-40
lines changed

2 files changed

+49
-40
lines changed

canopen/pdo/base.py

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ def __getitem_by_name(self, value):
215215
f"{', '.join(valid_values)}")
216216

217217
def __getitem__(self, key: Union[int, str]) -> "PdoVariable":
218-
var = None
219218
if isinstance(key, int):
220219
# there is a maximum available of 8 slots per PDO map
221220
if key in range(0, 8):
@@ -360,7 +359,8 @@ def _raw_from(param):
360359
subindex = (value >> 8) & 0xFF
361360
# Ignore the highest bit, it is never valid for <= 64 PDO length
362361
size = value & 0x7F
363-
if hasattr(self.pdo_node.node, "curtis_hack") and self.pdo_node.node.curtis_hack: # Curtis HACK: mixed up field order
362+
if getattr(self.pdo_node.node, "curtis_hack", False):
363+
# Curtis HACK: mixed up field order
364364
index = value & 0xFFFF
365365
subindex = (value >> 16) & 0xFF
366366
size = (value >> 24) & 0x7F
@@ -371,8 +371,10 @@ def _raw_from(param):
371371

372372
def save(self) -> None:
373373
"""Save PDO configuration for this map using SDO."""
374-
logger.info("Setting COB-ID 0x%X and temporarily disabling PDO",
375-
self.cob_id)
374+
if self.cob_id is None:
375+
logger.info("Skip saving %s: COB-ID was never set", self.com_record.od.name)
376+
return
377+
logger.info("Setting COB-ID 0x%X and temporarily disabling PDO", self.cob_id)
376378
self.com_record[1].raw = self.cob_id | PDO_NOT_VALID | (RTR_NOT_ALLOWED if not self.rtr_allowed else 0x0)
377379
if self.trans_type is not None:
378380
logger.info("Setting transmission type to %d", self.trans_type)
@@ -387,42 +389,44 @@ def save(self) -> None:
387389
logger.info("Setting SYNC start value to %d", self.sync_start_value)
388390
self.com_record[6].raw = self.sync_start_value
389391

390-
if self.map is not None:
391-
try:
392-
self.map_array[0].raw = 0
393-
except SdoAbortedError:
394-
# WORKAROUND for broken implementations: If the array has a
395-
# fixed number of entries (count not writable), generate dummy
396-
# mappings for an invalid object 0x0000:00 to overwrite any
397-
# excess entries with all-zeros.
398-
self._fill_map(self.map_array[0].raw)
399-
subindex = 1
400-
for var in self.map:
401-
logger.info("Writing %s (0x%04X:%02X, %d bits) to PDO map",
402-
var.name, var.index, var.subindex, var.length)
403-
if hasattr(self.pdo_node.node, "curtis_hack") and self.pdo_node.node.curtis_hack: # Curtis HACK: mixed up field order
404-
self.map_array[subindex].raw = (var.index |
405-
var.subindex << 16 |
406-
var.length << 24)
407-
else:
408-
self.map_array[subindex].raw = (var.index << 16 |
409-
var.subindex << 8 |
410-
var.length)
411-
subindex += 1
412-
try:
413-
self.map_array[0].raw = len(self.map)
414-
except SdoAbortedError as e:
415-
# WORKAROUND for broken implementations: If the array
416-
# number-of-entries parameter is not writable, we have already
417-
# generated the required number of mappings above.
418-
if e.code != 0x06010002:
419-
# Abort codes other than "Attempt to write a read-only
420-
# object" should still be reported.
421-
raise
422-
self._update_data_size()
392+
try:
393+
self.map_array[0].raw = 0
394+
except SdoAbortedError:
395+
# WORKAROUND for broken implementations: If the array has a
396+
# fixed number of entries (count not writable), generate dummy
397+
# mappings for an invalid object 0x0000:00 to overwrite any
398+
# excess entries with all-zeros.
399+
self._fill_map(self.map_array[0].raw)
400+
subindex = 1
401+
for var in self.map:
402+
logger.info("Writing %s (0x%04X:%02X, %d bits) to PDO map",
403+
var.name, var.index, var.subindex, var.length)
404+
if getattr(self.pdo_node.node, "curtis_hack", False):
405+
# Curtis HACK: mixed up field order
406+
self.map_array[subindex].raw = (var.index |
407+
var.subindex << 16 |
408+
var.length << 24)
409+
else:
410+
self.map_array[subindex].raw = (var.index << 16 |
411+
var.subindex << 8 |
412+
var.length)
413+
subindex += 1
414+
try:
415+
self.map_array[0].raw = len(self.map)
416+
except SdoAbortedError as e:
417+
# WORKAROUND for broken implementations: If the array
418+
# number-of-entries parameter is not writable, we have already
419+
# generated the required number of mappings above.
420+
if e.code != 0x06010002:
421+
# Abort codes other than "Attempt to write a read-only
422+
# object" should still be reported.
423+
raise
424+
self._update_data_size()
423425

424426
if self.enabled:
425-
self.com_record[1].raw = self.cob_id | (RTR_NOT_ALLOWED if not self.rtr_allowed else 0x0)
427+
cob_id = self.cob_id | (RTR_NOT_ALLOWED if not self.rtr_allowed else 0x0)
428+
logger.info("Setting COB-ID 0x%X and re-enabling PDO", cob_id)
429+
self.com_record[1].raw = cob_id
426430
self.subscribe()
427431

428432
def subscribe(self) -> None:
@@ -521,7 +525,7 @@ def remote_request(self) -> None:
521525
Silently ignore if not allowed.
522526
"""
523527
if self.enabled and self.rtr_allowed:
524-
self.pdo_node.network.send_message(self.cob_id, None, remote=True)
528+
self.pdo_node.network.send_message(self.cob_id, bytes(), remote=True)
525529

526530
def wait_for_reception(self, timeout: float = 10) -> float:
527531
"""Wait for the next transmit PDO.
@@ -600,7 +604,7 @@ def set_data(self, data: bytes):
600604
cur_msg_data = cur_msg_data & bitwise_not
601605
# Set the new data on the correct position
602606
data = (data << bit_offset) | cur_msg_data
603-
data = od_struct.pack_into(self.pdo_parent.data, byte_offset, data)
607+
od_struct.pack_into(self.pdo_parent.data, byte_offset, data)
604608
else:
605609
self.pdo_parent.data[byte_offset:byte_offset + len(data)] = data
606610

test/test_pdo.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ def test_bit_mapping(self):
5555
self.assertEqual(node.tpdo[0x2002].raw, 0xf)
5656
self.assertEqual(node.pdo[0x1600][0x2002].raw, 0xf)
5757

58+
def test_save_pdo(self):
59+
node = canopen.Node(1, EDS_PATH)
60+
node.tpdo.save()
61+
node.rpdo.save()
62+
5863

5964
if __name__ == "__main__":
6065
unittest.main()

0 commit comments

Comments
 (0)