Skip to content

Commit 6a4ca11

Browse files
Save the passed node ID to the resulting OD in import_od() (#484)
Only for DCF-files (which include a DeviceComissioning section), the Node-ID from the file is stored in the ObjectDictionary instance. When given an override value via the `import_od(..., node_id=...)` argument, that was however not applied to the OD attribute, but only used for $NODEID interpolation. Make sure the interpolated values match the stored node_id in this case. Also handle a missing NodeID option within the DeviceComissioning section gracefully, instead of raising an exception.
1 parent 2938a90 commit 6a4ca11

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

canopen/objectdictionary/eds.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,11 @@ def import_eds(source, node_id):
8686

8787
if eds.has_section("DeviceComissioning"):
8888
od.bitrate = int(eds.get("DeviceComissioning", "Baudrate")) * 1000
89-
od.node_id = int(eds.get("DeviceComissioning", "NodeID"), 0)
90-
node_id = node_id or od.node_id
89+
90+
if node_id is None:
91+
if val := eds.get("DeviceComissioning", "NodeID", fallback=None):
92+
node_id = int(val, base=0)
93+
od.node_id = node_id
9194

9295
for section in eds.sections():
9396
# Match dummy definitions

test/sample.eds

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ NrOfTXPDO=4
3030
LSS_Supported=0
3131

3232
[DeviceComissioning]
33-
NodeID=2
33+
NodeID=0x10
3434
NodeName=Some name
3535
Baudrate=500
3636
NetNumber=0

test/test_eds.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
from canopen.objectdictionary.eds import _signed_int_from_hex
55
from canopen.utils import pretty_index
66

7-
EDS_PATH = os.path.join(os.path.dirname(__file__), 'sample.eds')
7+
8+
SAMPLE_EDS = os.path.join(os.path.dirname(__file__), 'sample.eds')
9+
DATATYPES_EDS = os.path.join(os.path.dirname(__file__), 'datatypes.eds')
810

911

1012
class TestEDS(unittest.TestCase):
@@ -48,7 +50,7 @@ class TestEDS(unittest.TestCase):
4850
}
4951

5052
def setUp(self):
51-
self.od = canopen.import_od(EDS_PATH, 2)
53+
self.od = canopen.import_od(SAMPLE_EDS, 2)
5254

5355
def test_load_nonexisting_file(self):
5456
with self.assertRaises(IOError):
@@ -59,10 +61,34 @@ def test_load_unsupported_format(self):
5961
canopen.import_od(__file__)
6062

6163
def test_load_file_object(self):
62-
with open(EDS_PATH) as fp:
64+
with open(SAMPLE_EDS) as fp:
6365
od = canopen.import_od(fp)
6466
self.assertTrue(len(od) > 0)
6567

68+
def test_load_implicit_nodeid(self):
69+
# sample.eds has a DeviceComissioning section with NodeID set to 0x10.
70+
od = canopen.import_od(SAMPLE_EDS)
71+
self.assertEqual(od.node_id, 16)
72+
73+
def test_load_implicit_nodeid_fallback(self):
74+
import io
75+
76+
# First, remove the NodeID option from DeviceComissioning.
77+
with open(SAMPLE_EDS) as f:
78+
lines = [L for L in f.readlines() if not L.startswith("NodeID=")]
79+
with io.StringIO("".join(lines)) as buf:
80+
buf.name = "mock.eds"
81+
od = canopen.import_od(buf)
82+
self.assertIsNone(od.node_id)
83+
84+
# Next, try an EDS file without a DeviceComissioning section.
85+
od = canopen.import_od(DATATYPES_EDS)
86+
self.assertIsNone(od.node_id)
87+
88+
def test_load_explicit_nodeid(self):
89+
od = canopen.import_od(SAMPLE_EDS, node_id=3)
90+
self.assertEqual(od.node_id, 3)
91+
6692
def test_variable(self):
6793
var = self.od['Producer heartbeat time']
6894
self.assertIsInstance(var, canopen.objectdictionary.ODVariable)

0 commit comments

Comments
 (0)