devicetree: better DT_PROP_BY_IDX()/DT_FOREACH_PROP_ELEM() support
Support use of these macros with properties of type phandle and
string by allowing iterating over:
- a phandle as if it were a phandles of length 1, for convenience and
consistency with our ability to take its length (and getting 1)
- the non-null characters in a string: we exclude the null for
consistency with the return value of DT_PROP_LEN() on string
properties, which, like strlen(), does not include the null
With this and a previous patch expanding the usage of DT_PROP_LEN(),
there is now a relationship between being able to take a property's
logical length with DT_PROP_LEN() and being able to iterate over its
logical elements with DT_FOREACH_PROP_ELEM(). Explain this in the
documentation.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py
index 31a02c0..2394e3a 100755
--- a/scripts/dts/gen_defines.py
+++ b/scripts/dts/gen_defines.py
@@ -32,12 +32,6 @@
from devicetree import edtlib
-# The set of binding types whose values can be iterated over with
-# DT_FOREACH_PROP_ELEM(). If you change this, make sure to update the
-# doxygen string for that macro.
-FOREACH_PROP_ELEM_TYPES = set(['string', 'array', 'uint8-array', 'string-array',
- 'phandles', 'phandle-array'])
-
class LogFormatter(logging.Formatter):
'''A log formatter that prints the level name in lower case,
for compatibility with earlier versions of edtlib.'''
@@ -651,6 +645,12 @@
macro2val[macro + "_STRING_TOKEN"] = prop.val_as_token
# DT_N_<node-id>_P_<prop-id>_IDX_<i>_STRING_UPPER_TOKEN
macro2val[macro + "_STRING_UPPER_TOKEN"] = prop.val_as_token.upper()
+ # DT_N_<node-id>_P_<prop-id>_IDX_0:
+ # DT_N_<node-id>_P_<prop-id>_IDX_0_EXISTS:
+ # Allows treating the string like a degenerate case of a
+ # string-array of length 1.
+ macro2val[macro + "_IDX_0"] = quote_str(prop.val)
+ macro2val[macro + "_IDX_0_EXISTS"] = 1
if prop.enum_index is not None:
# DT_N_<node-id>_P_<prop-id>_ENUM_IDX
@@ -692,33 +692,32 @@
macro2val[macro + f"_IDX_{i}"] = subval
macro2val[macro + f"_IDX_{i}_EXISTS"] = 1
- if prop.type in FOREACH_PROP_ELEM_TYPES:
+ plen = prop_len(prop)
+ if plen is not None:
# DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM
macro2val[f"{macro}_FOREACH_PROP_ELEM(fn)"] = \
' \\\n\t'.join(
f'fn(DT_{node.z_path_id}, {prop_id}, {i})'
- for i in range(len(prop.val)))
+ for i in range(plen))
# DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_SEP
macro2val[f"{macro}_FOREACH_PROP_ELEM_SEP(fn, sep)"] = \
' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
f'fn(DT_{node.z_path_id}, {prop_id}, {i})'
- for i in range(len(prop.val)))
+ for i in range(plen))
# DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_VARGS
macro2val[f"{macro}_FOREACH_PROP_ELEM_VARGS(fn, ...)"] = \
' \\\n\t'.join(
f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)'
- for i in range(len(prop.val)))
+ for i in range(plen))
# DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_SEP_VARGS
macro2val[f"{macro}_FOREACH_PROP_ELEM_SEP_VARGS(fn, sep, ...)"] = \
' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)'
- for i in range(len(prop.val)))
+ for i in range(plen))
- plen = prop_len(prop)
- if plen is not None:
# DT_N_<node-id>_P_<prop-id>_LEN
macro2val[macro + "_LEN"] = plen
@@ -786,6 +785,11 @@
# Returns the property's length if and only if we should generate
# a _LEN macro for the property. Otherwise, returns None.
#
+ # The set of types handled here coincides with the allowable types
+ # that can be used with DT_PROP_LEN(). If you change this set,
+ # make sure to update the doxygen string for that macro, and make
+ # sure that DT_FOREACH_PROP_ELEM() works for the new types too.
+ #
# This deliberately excludes ranges, dma-ranges, reg and interrupts.
# While they have array type, their lengths as arrays are
# basically nonsense semantically due to #address-cells and