devicetree: add new for-each macros
Add two new for-each macros: - DT_FOREACH_STATUS_OKAY(compat, fn) - DT_FOREACH_STATUS_OKAY_VARGS(compat, fn, ...) These can be used to expand "fn" once for every status "okay" node in the devicetree which has a given compatible. The intended use case is to allow doing something in C once for each node of a compatible, but outside of a device driver. E.g. an application might want to collect an array of structures for a compatible, where each structure is initialized from a node. In such cases we don't want people to be forced into using DT_DRV_COMPAT and instance numbers, because that's in general a hint that you're doing something driver-like. Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
parent
e7d42ff879
commit
56da140791
2 changed files with 123 additions and 0 deletions
|
@ -1714,6 +1714,105 @@
|
|||
#define DT_FOREACH_PROP_ELEM_VARGS(node_id, prop, fn, ...) \
|
||||
DT_CAT4(node_id, _P_, prop, _FOREACH_PROP_ELEM_VARGS)(fn, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Call "fn" on all nodes with compatible DT_DRV_COMPAT
|
||||
* and status "okay"
|
||||
*
|
||||
* This macro expands to:
|
||||
*
|
||||
* fn(node_id_1) fn(node_id_2) ... fn(node_id_n)
|
||||
*
|
||||
* where each "node_id_<i>" is a node identifier for some node with
|
||||
* compatible "compat" and status "okay". Whitespace is added between
|
||||
* expansions as shown above.
|
||||
*
|
||||
* Example devicetree fragment:
|
||||
*
|
||||
* / {
|
||||
* a {
|
||||
* compatible = "foo";
|
||||
* status = "okay";
|
||||
* };
|
||||
* b {
|
||||
* compatible = "foo";
|
||||
* status = "disabled";
|
||||
* };
|
||||
* c {
|
||||
* compatible = "foo";
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* DT_FOREACH_STATUS_OKAY(foo, DT_NODE_PATH)
|
||||
*
|
||||
* This expands to one of the following:
|
||||
*
|
||||
* "/a" "/c"
|
||||
* "/c" "/a"
|
||||
*
|
||||
* "One of the following" is because no guarantees are made about the
|
||||
* order that node identifiers are passed to "fn" in the expansion.
|
||||
*
|
||||
* (The "/c" string literal is present because a missing status
|
||||
* property is always treated as if the status were set to "okay".)
|
||||
*
|
||||
* Note also that "fn" is responsible for adding commas, semicolons,
|
||||
* or other terminators as needed.
|
||||
*
|
||||
* @param compat lowercase-and-underscores devicetree compatible
|
||||
* @param fn Macro to call for each enabled node. Must accept a
|
||||
* node_id as its only parameter.
|
||||
*/
|
||||
#define DT_FOREACH_STATUS_OKAY(compat, fn) \
|
||||
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \
|
||||
(UTIL_CAT(DT_FOREACH_OKAY_, compat)(fn)), \
|
||||
())
|
||||
|
||||
/**
|
||||
* @brief Invokes "fn" for each status "okay" node of a compatible
|
||||
* with multiple arguments.
|
||||
*
|
||||
* This is like DT_FOREACH_STATUS_OKAY() except you can also pass
|
||||
* additional arguments to "fn".
|
||||
*
|
||||
* Example devicetree fragment:
|
||||
*
|
||||
* / {
|
||||
* a {
|
||||
* compatible = "foo";
|
||||
* val = <3>;
|
||||
* };
|
||||
* b {
|
||||
* compatible = "foo";
|
||||
* val = <4>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* #define MY_FN(node_id, operator) DT_PROP(node_id, val) operator
|
||||
* x = DT_FOREACH_STATUS_OKAY_VARGS(foo, MY_FN, +) 0;
|
||||
*
|
||||
* This expands to one of the following:
|
||||
*
|
||||
* x = 3 + 4 + 0;
|
||||
* x = 4 + 3 + 0;
|
||||
*
|
||||
* i.e. it sets x to 7. As with DT_FOREACH_STATUS_OKAY(), there are no
|
||||
* guarantees about the order nodes appear in the expansion.
|
||||
*
|
||||
* @param compat lowercase-and-underscores devicetree compatible
|
||||
* @param fn Macro to call for each enabled node. Must accept a
|
||||
* node_id as its only parameter.
|
||||
* @param ... Additional arguments to pass to "fn"
|
||||
*/
|
||||
#define DT_FOREACH_STATUS_OKAY_VARGS(compat, fn, ...) \
|
||||
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \
|
||||
(UTIL_CAT(DT_FOREACH_OKAY_VARGS_, \
|
||||
compat)(fn, __VA_ARGS__)), \
|
||||
())
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -1265,6 +1265,30 @@ static void test_foreach_status_okay(void)
|
|||
* for-each-property type macros.
|
||||
*/
|
||||
unsigned int val;
|
||||
const char *str;
|
||||
|
||||
/* This should expand to something like:
|
||||
*
|
||||
* "/test/enum-0" "/test/enum-1"
|
||||
*
|
||||
* but there is no guarantee about the order of nodes in the
|
||||
* expansion, so we test both.
|
||||
*/
|
||||
str = DT_FOREACH_STATUS_OKAY(vnd_enum_holder, DT_NODE_PATH);
|
||||
zassert_true(!strcmp(str, "/test/enum-0/test/enum-1") ||
|
||||
!strcmp(str, "/test/enum-1/test/enum-0"), "");
|
||||
|
||||
#undef MY_FN
|
||||
#define MY_FN(node_id, operator) DT_ENUM_IDX(node_id, val) operator
|
||||
/* This should expand to something like:
|
||||
*
|
||||
* 0 + 2 + 3
|
||||
*
|
||||
* and order of expansion doesn't matter, since we're adding
|
||||
* the values all up.
|
||||
*/
|
||||
val = DT_FOREACH_STATUS_OKAY_VARGS(vnd_enum_holder, MY_FN, +) 3;
|
||||
zassert_equal(val, 5, "");
|
||||
|
||||
/*
|
||||
* Make sure DT_INST_FOREACH_STATUS_OKAY can be called from functions
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue