scripts: edtlib: Add a Device.children attribute with child Devices

API oversight. This was meant to be there all along together with
Device.parent, for navigating the devicetree, but since a need for it
never came up in gen_defines.py, it got overlooked.

Devices are just devicetree nodes augmented with binding information and
some interpretation of devicetree properties. I wonder if the name
should be changed to something like edtlib.Node to make that clearer.
Calling something like a flash partition a "device" is a bit weird, as
Galak pointed out.

I think I went with Device originally to avoid confusion with
dtlib.Node, but since edtlib users don't directly interact with dtlib,
it might not be that confusing in practice.

Piggyback some documentation clarifications.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
Ulf Magnusson 2019-09-21 04:14:33 +02:00 committed by Kumar Gala
commit 110526ec0e
4 changed files with 59 additions and 13 deletions

View file

@ -333,8 +333,9 @@ class EDT:
class Device: class Device:
""" """
Represents a device. There's a one-to-one correspondence between device Represents a device, which is a devicetree node augmented with information
tree nodes and Devices. from bindings and some interpretation of devicetree properties. There's a
one-to-one correspondence between device tree nodes and Devices.
These attributes are available on Device objects: These attributes are available on Device objects:
@ -357,7 +358,12 @@ class Device:
if the node has no 'label' if the node has no 'label'
parent: parent:
The parent Device, or None if there is no parent The Device instance for the devicetree parent of the Device, or None if
there is no parent
children:
A dictionary with the Device instances for the devicetree children of the
Device, indexed by name
enabled: enabled:
True unless the device's node has 'status = "disabled"' True unless the device's node has 'status = "disabled"'
@ -479,6 +485,15 @@ class Device:
"See the class docstring" "See the class docstring"
return self.edt._node2dev.get(self._node.parent) return self.edt._node2dev.get(self._node.parent)
@property
def children(self):
"See the class docstring"
# Could be initialized statically too to preserve identity, but not
# sure if needed. Parent Devices being initialized before their
# children would need to be kept in mind.
return {name: self.edt._node2dev[node]
for name, node in self._node.nodes.items()}
@property @property
def enabled(self): def enabled(self):
"See the class docstring" "See the class docstring"

View file

@ -273,6 +273,19 @@
}; };
}; };
//
// For testing Device.parent and Device.children
//
parent {
child-1 {
};
child-2 {
grandchild {
};
};
};
// //
// For testing 'include:' // For testing 'include:'
// //

View file

@ -9,10 +9,9 @@ import sys
import dtlib import dtlib
# Test suite for dtlib.py. Can be run directly as an executable. # Test suite for dtlib.py. Run it directly as an executable, in this directory:
# #
# This script expects to be run from the directory its in. This simplifies # $ ./testdtlib.py
# things, as paths in the output can be assumed below.
# TODO: Factor out common code from error tests # TODO: Factor out common code from error tests

View file

@ -7,13 +7,13 @@ import sys
import edtlib import edtlib
# Test suite for edtlib.py. Mostly uses string comparisons via the various # Test suite for edtlib.py. Run it directly as an executable, in this
# __repr__() methods. Can be run directly as an executable. # directory:
# #
# This script expects to be run from the directory its in. This simplifies # $ ./testedtlib.py
# things, as paths in the output can be assumed below.
# #
# test.dts is the test file, and test-bindings/ has bindings. # test.dts is the test file. test-bindings/ has bindings. The tests mostly use
# string comparisons via the various __repr__() methods.
def run(): def run():
@ -25,13 +25,15 @@ def run():
def fail(msg): def fail(msg):
sys.exit("test failed: " + msg) sys.exit("test failed: " + msg)
def verify_streq(actual, expected): def verify_eq(actual, expected):
actual = str(actual)
if actual != expected: if actual != expected:
# Put values on separate lines to make it easy to spot differences # Put values on separate lines to make it easy to spot differences
fail("not equal (expected value last):\n'{}'\n'{}'" fail("not equal (expected value last):\n'{}'\n'{}'"
.format(actual, expected)) .format(actual, expected))
def verify_streq(actual, expected):
verify_eq(str(actual), expected)
edt = edtlib.EDT("test.dts", ["test-bindings"]) edt = edtlib.EDT("test.dts", ["test-bindings"])
# #
@ -97,6 +99,23 @@ def run():
verify_streq(edt.get_dev("/reg-nested-ranges/grandparent/parent/node").regs, verify_streq(edt.get_dev("/reg-nested-ranges/grandparent/parent/node").regs,
"[<Register, addr: 0x30000000200000001, size: 0x1>]") "[<Register, addr: 0x30000000200000001, size: 0x1>]")
#
# Test Device.parent and Device.children
#
verify_eq(edt.get_dev("/").parent, None)
verify_streq(edt.get_dev("/parent/child-1").parent,
"<Device /parent in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent/child-2/grandchild").parent,
"<Device /parent/child-2 in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent").children,
"{'child-1': <Device /parent/child-1 in 'test.dts', no binding>, 'child-2': <Device /parent/child-2 in 'test.dts', no binding>}")
verify_eq(edt.get_dev("/parent/child-1").children, {})
# #
# Test 'include:' and the legacy 'inherits: !include ...' # Test 'include:' and the legacy 'inherits: !include ...'
# #