Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmake: introduce snippets for common configuration #40669

Closed
wants to merge 4 commits into from
Closed

cmake: introduce snippets for common configuration #40669

wants to merge 4 commits into from

Conversation

JordanYates
Copy link
Collaborator

@JordanYates JordanYates commented Nov 25, 2021

Introduces the concept of snippet's to application configuration. A snippet is a piece of functionality that is not the default behaviour of a board, but is a common configuration that users may wish to apply.

One example snippet concept is "usb" which may route the console to USB instead of a serial port. Another common snippet could be "mcuboot", which would define the flash partitions required for applications to be loaded by a bootloader.

The name "snippet" was chosen mainly to avoid collisions with existing terms. Alternatives considered include:

  • overlay (collision with devicetree overlay concept)
  • config (collision with Kconfig)
  • fragment (collision with .conf files [Kconfig fragments])
  • part (collision with --pristine build option, flash partitions)
  • layout (implies memory configuration)

The Oxford dictionary definition of snippet appears to match this concept well, "a small piece or brief extract".

Snippets are a required devicetree .overlay file and an optional .conf file that are appended to the existing CMake variables DTC_OVERLAY_FILE and CONF_FILE. The initial search paths for these files are ${APPLICATION_SOURCE_DIR}/${BOARD}/snippets and ${BOARD_DIR}/snippets, with the application directory having precedence to allow for overriding board defaults.

This is a first step towards #34167, as it enables generating zephyr.dts files with only the partitions required by an application.
Related to the Zephyr developer summit talk "Common Application Configuration for boards".

Please keep bike-shedding about the name "snippet" to a minimum, I fully expect this to go to "dev-review" which would decide the name anyway 😄.

@JordanYates
Copy link
Collaborator Author

CC @carlescufi @tejlmand @mrrosen

@carlescufi
Copy link
Member

Is this related or can address what is trying to be accomplished here by @jfischer-no?

@carlocaione
Copy link
Collaborator

I choose to ignore the bike-shedding suggestion just to point out that yocto calls these configuration fragments ;)

Copy link
Collaborator

@tejlmand tejlmand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for one more idea.

Some initial comments on the approach, mostly based on the commit message description:

One example snippet concept is "usb" which may route the console to USB
instead of a serial port.

This is so far the most valid use-case we have.

Another common snippet could be "mcuboot",
which would define the flash partitions required for applications to
be loaded by a bootloader.

I believe the mcuboot use-case should be addressed with the multi image support that keeps popping up.
There is finally a RFC trying to address at a higher level than building the Zephyr sample build infrastructure, #40555.

The name "snippet" was chosen mainly to avoid collisions with existing
terms.

Like linker snippets 😆

zephyr/cmake/extensions.cmake

Lines 1178 to 1184 in 6ee8182

set(sections_path "${snippet_base}/snippets-sections.ld")
set(ram_sections_path "${snippet_base}/snippets-ram-sections.ld")
set(data_sections_path "${snippet_base}/snippets-data-sections.ld")
set(rom_start_path "${snippet_base}/snippets-rom-start.ld")
set(noinit_path "${snippet_base}/snippets-noinit.ld")
set(rwdata_path "${snippet_base}/snippets-rwdata.ld")
set(rodata_path "${snippet_base}/snippets-rodata.ld")

Guess we will collide with something regardless of the term we choose.
That said, snippet is not bad.

Snippets are a required devicetree .overlay file and an optional
.conf file that are appended to the existing CMake variables
DTC_OVERLAY_FILE and CONF_FILE.

Why is the dtc overlay required, and the Kconfig optional.
I see no reasoning for this decision, so could you please elaborate on this.

The initial search paths for these
files are ${APPLICATION_SOURCE_DIR}/${BOARD}/snippets and
${BOARD_DIR}/snippets, with the application directory having
precedence to allow for overriding board defaults.

But what is the interaction with sample specific overlay ?
How is it known if a snippet is valid to apply in a given sample.

With this PR, then a board and a sample having:

boards/<arch>/my_board/snippets/awesome.overlay
boards/<arch>/my_board/snippets/awesome.conf

samples/cool_stuff/app.overlay

or
samples/cool_stuff/boards/my_board.overlay
samples/cool_stuff/boards/my_board.conf

I know that cool_stuff works with the regular board configuration, but how will a user know whether awesome snippet is working or has been tested with cool_stuff ?
And how is it intended to be ensured that awesome snippet works thoughout the build system. (Testing all samples for this board with this snippet 😮 )

Current solution, where a awesome.conf / awesome.overlay resides in a sample then I know that sample is compatible with the settings in awesome.conf / awesome.overlay.
Or if the sample has app.overlay, then I know it works with that.

I agree that the usb use-case is very generic, and should not cause trouble, but what is the threshold for when something can be made a snippet ?
And is usb really our only good use-case on this.

@@ -22,7 +22,7 @@
BUILD_USAGE = '''\
west build [-h] [-b BOARD] [-d BUILD_DIR]
[-t TARGET] [-p {auto, always, never}] [-c] [--cmake-only]
[-n] [-o BUILD_OPT] [-f]
[-n] [-o BUILD_OPT] [-f] [-s SNIPPET]
Copy link
Collaborator

@tejlmand tejlmand Nov 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two comments on this:

  • Although -s has been deprecated for some time, then I think it's good practice to have a period between removing the argument before using that same argument for something new.
  • Why should snippet have it's own west build argument when CONF_FILE, DTC_OVERLAY_FILE, SHIELD etc. doesn't have ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Although -s has been deprecated for some time, then I think it's good practice to have a period between removing the argument before using that same argument for something new.

In an ideal world yes, but the end result is going to be the same. If -s is removed, any scripts using it will crash. If -s is reused, any scripts using it will crash. Unfortunately I can't go back and remove it a year ago. Of course if the name changes from "snippet" then there is no need to use -s.

  • Why should snippet have it's own west build argument when CONF_FILE, DTC_OVERLAY_FILE, SHIELD etc. doesn't have?

Because its goal is to cover common use cases, which IMO means the ease-of-use of west build -b board -s usb samples/basic/minimal over west build -b board samples/basic/minimal -- -DSNIPPETS="usb" warrants it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say -DOVERLAY_CONFIG or DTC_OVERLAY_FILE are much better candidates for having extra arguments than snippets.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree; I think snippets do rise to the level of deserving their own option.

I want to ask what the practical differences between snippets and shields are at this point, in terms of their behavior. Shields seem to be a special case of snippets, morally speaking.

Taking @petejohanson since he's taken an interest in adding more comprehensive shield related options to west build elsewhere.

@@ -0,0 +1,40 @@
/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should do this for mcuboot.

If we should do anything related to partition layout when mcuboot is enabled, then we should do this on higher level where we build both the sample and mcuboot, aka as multi image, see this RFC: #40555

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tejlmand, exactly how is RFC #40555 going to handle the problem that is addressed by the present PR. What is done here is overruling the definition that is given in the dts for the flash layout. More specific what is going to be the solution in the multi-image PR to support:
a. A non-mcuboot image,
b. A mcuboot image with only the slot0 image generated,
c. A mcuboot image with mcuboot + slot0 image generated,
(d. A mcuboot + slot1 image (encrypted) generated),

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tejlmand, exactly how is RFC #40555 going to handle the problem that is addressed by the present PR. What is done here is overruling the definition that is given in the dts for the flash layout. More specific what is going to be the solution in the multi-image PR to support:

For this PR, I only see a single mcuboot, so that must be a (being the case without this PR) and b.

Not c and d.

Regarding #40555, the topic you raise is outside the specific scope of that PR, but it opens up for a broader use-case, so let me sketch the general idea.

With #40555 it is possible to build the sample with or without mcuboot (or any other multi image, like the openamp_remote case).

In such a scenario, which would also be preparing for system devicetree, we can then apply a given set of overlay when a given bootloader is used.

If mcuboot is enabled when building, then we can ensure a devicetree setup with a flash layout suitable for mcuboot is selected and applied to all images part of the build.
This will further avoid the risk of the application being build with one snippet and mcuboot with another because you forgot to apply the same settings there.

The #40555 itself doesn't address this possibility, because it's just an RFC and I have tried to find the balance between amount of time spent to present the idea, while not yet spend too much time if the direction is rejected.

@carlescufi
Copy link
Member

I choose to ignore the bike-shedding suggestion just to point out that yocto calls these configuration fragments ;)

That's terrible given that .conf files are called "Kconfig fragments". Very confusing.

@JordanYates
Copy link
Collaborator Author

Another common snippet could be "mcuboot",
which would define the flash partitions required for applications to
be loaded by a bootloader.

I believe the mcuboot use-case should be addressed with the multi image support that keeps popping up.
There is finally a RFC trying to address at a higher level than building the Zephyr sample build infrastructure, #40555.

This is not intending to perform a multi-image build, or even multi-image support. It is aimed at the one outcome from the "Common application configuration for boards" talk that I thought was broadly agreed on. Namely that zephyr.dts should only contain information that is valid for that particular build. There is nothing stopping #40555 from setting the "mcuboot" snippet to pull in the correct flash partitions and Kconfig settings.

The name "snippet" was chosen mainly to avoid collisions with existing
terms.

Like linker snippets 😆

Whoops, you deserve credit for the name, I forgot that is where I heard it.

Why is the dtc overlay required, and the Kconfig optional.
I see no reasoning for this decision, so could you please elaborate on this.

Because my primary use case was for applying devicetree overlays (fixing flash partitions and chosen nodes). The Kconfig file can easily be made required if that is the consensus view.

I know that cool_stuff works with the regular board configuration, but how will a user know whether awesome snippet is working or has been tested with cool_stuff ? And how is it intended to be ensured that awesome snippet works thoughout the build system. (Testing all samples for this board with this snippet 😮 )

Because at least initially I see the scope for snippets to be functionality that is not specific to any particular application. If the mcuboot snippet is tested for a board once anywhere, you can be quite confident that it will work on any sample/application. I don't consider it much different from the current setup, how do I know that samples/basic/servo_motor will work on anything other than a bbc_microbit? We can't guarantee everything. Test all board level snippets against samples/basic/minimal to at least ensure they compile, and test board specific snippets in sample folders (not that I see much use for that in-tree).

And is usb really our only good use-case on this.

No. As I've said many times in many places, there are problems that can only be solved cleanly if zephyr.dts is minimal and correct. This is a mechanism to provide that, which is why I believe mcuboot should be a snippet for every board that supports it. If that and USB are the only two in-tree uses, I still think it is worthwhile.

@tejlmand
Copy link
Collaborator

This is not intending to perform a multi-image build, or even multi-image support. It is aimed at the one outcome from the "Common application configuration for boards" talk that I thought was broadly agreed on. Namely that zephyr.dts should only contain information that is valid for that particular build. There is nothing stopping #40555 from setting the "mcuboot" snippet to pull in the correct flash partitions and Kconfig settings.

I know, but in #40555 I try to avoid create two different workflows for the user when using west build.
What I mean with that, is that if you do west build ... -- -DCONFIG_SOMETHING=y today, you still do the same west build after that PR.
And you can opt-in to include mcuboot in that west build with west build ... -- -DCONFIG_SOMETHING=y -DCONFIG_WB_BOOTLOADER_MCUBOOT=y.
And as you see, you are still allowed to use the same flags as always.

If introducing a new snippet workflow including the mcuboot snippet, then I see some risks in using that -DSNIPPETS=mcuboot snippet workflow colliding with the west build mcuboot inclusion.
Let's say #40555 starts applying the same snippet, for example: west build ... -- -DSNIPPETS=mcuboot -DCONFIG_WB_BOOTLOADER_MCUBOOT=y then how should that be treated ?

Therefore I would prefer not to try addressing / creating a new workflow for the MCUboot use-case just now.

I don't consider it much different from the current setup, how do I know that samples/basic/servo_motor will work on anything other than a bbc_microbit? We can't guarantee everything.

No, but the difference here is that for a sample like servo_motor, we do guarantee that it works for that board:

platform_allow: bbc_microbit

and similar in the docs: https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/basic/servo_motor/README.rst

Whereas as soon as we start placing configs in a common location we must be much clearer on what users may expect.

I do notice that your snippets follows the board, which helps a lot on the concern regarding just a single common location, but it also means a user may not know if -s mcuboot will work (but should find out pretty fast).

mcuboot and usb are good cases.
My concern is more regarding later, when someone wants to have some-snippet merged.
What will be the threshold for new snippets ?

The snippets doesn't state what samples they are guaranteed to work with, and samples doesn't stated which snippets are supported.

Why is the dtc overlay required, and the Kconfig optional.
I see no reasoning for this decision, so could you please elaborate on this.

Because my primary use case was for applying devicetree overlays (fixing flash partitions and chosen nodes). The Kconfig file can easily be made required if that is the consensus view.

I was just curious, cause if devicetree overlay was all you needed, then another option could be to allow DTC_OVERLAY_FILE to lookup relative to board dir, for example DTC_OVERLAY_FILE=overlay/usb.overlay.

And for the application dir we already have the DTC_OVERLAY_FILE and CONF_FILE / OVERLAY_CONFIG if only needing to apply one without the other.

Therefore I was wondering if it would make more sense that a new term like snippets would mean a set with a devicetree overlay + a Kconfig fragment.
We already have a term when applying one of them without the other.

Copy link
Contributor

@mbolivar-nordic mbolivar-nordic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this. It's small and seems to address exactly the scope we debated at length after last year's Zephyr Developers Summit. I have a couple of quibbles here and there but I'm generally +1.

@@ -99,8 +99,6 @@ def do_add_parser(self, parser_adder):
# flags

parser.add_argument('-b', '--board', help='board to build for')
# Hidden option for backwards compatibility
parser.add_argument('-s', '--source-dir', help=argparse.SUPPRESS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally get what you're doing here, and although I use this option every day, I would be willing to part ways with it in the name of making progress on this more important issue (assuming "snippet" is chosen).

But there are a few places in the docs that are using still:

doc/guides/west/sign.rst
29:   west build -b YOUR_BOARD -s bootloader/mcuboot/boot/zephyr -d build-mcuboot
30:   west build -b YOUR_BOARD -s zephyr/samples/hello_world -d build-hello-signed -- \

doc/guides/dts/howtos.rst
35:   west build -b qemu_cortex_m3 -s samples/hello_world --cmake-only

Those would need cleanup as well, pending resolution of the bikeshed debate.

@@ -22,7 +22,7 @@
BUILD_USAGE = '''\
west build [-h] [-b BOARD] [-d BUILD_DIR]
[-t TARGET] [-p {auto, always, never}] [-c] [--cmake-only]
[-n] [-o BUILD_OPT] [-f]
[-n] [-o BUILD_OPT] [-f] [-s SNIPPET]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree; I think snippets do rise to the level of deserving their own option.

I want to ask what the practical differences between snippets and shields are at this point, in terms of their behavior. Shields seem to be a special case of snippets, morally speaking.

Taking @petejohanson since he's taken an interest in adding more comprehensive shield related options to west build elsewhere.

@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@tejlmand
Copy link
Collaborator

tejlmand commented Feb 18, 2022

@JordanYates @mbolivar-nordic @jfischer-no I have done some thinking on this.

While I believe the snippets concept proposed in this PR makes a lot of sense, then I did some thinking related to the usb use-case.

We have board revisions, and a while back we discussed generalizing this into board variants (on slack as I recall it), where revision is just a specialized kind of a variant.

Now, in addition to a board providing custom variants, Zephyr can provide common variants, like a cdc_acm.
That may allow users to build the same board for a cdc_acm variant, like this:
nrf52840dk_nrf52840 or nrf52840dk_nrf52840@cdc_acm

Just like boards can default to a specific revision, for example nrf9160dk_nrf9160 --> nrf9160dk_nrf9160@0.7.0
Then a board which requires cdc_acm always, for example: ble654_usb, then building for bl654_usb is identical to building bl654_usb@cdc_acm.

And just like with revisions, it can be made visible (and testable by the build system) whether a given variant is supported, similar to what is done for the revision:

DEFAULT_REVISION 0.7.0
VALID_REVISIONS 0.7.0 0.14.0

This further allow users to re-use existing infrastructure where Kconfig snippets and DT overlay may be applied automatically depending on board, variant, (and revision).

I don't see variant support in conflict with snippets, they both serve a purpose.
But the variant will allow to formalize and re-use variants between boards and make it more visible to users what variant type a given board supports.

@codecov-commenter

This comment was marked as spam.

Copy link
Collaborator

@jfischer-no jfischer-no left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This neither makes sense nor is it helpful to provide a generic board-wide (or tree-wide) configuration, as it is possible with our shield support, see #40645.

Different configuration on a board level are already possible with board version. On application level DT and *.conf overlays are supported. The example given regarding USB has neither sense nor necessity, worse, it leads some to think that this can be alternative-to / help-with #40645.

Compared to current shield support (even if shield is hardware configuration related) snippets here do not provide support for overall configuration, Kconfig files are not supported, no documentation, no documentation support.

I probably do not quite understand the motivation for these changes, for my part related to #40645, I suggest to rename shield to something more generic and derive from it shield for hardware and foobar for specific configuration.

@github-actions github-actions bot removed the Stale label Feb 19, 2022
@tejlmand
Copy link
Collaborator

This neither makes sense nor is it helpful to provide a generic board-wide (or tree-wide) configuration, as it is possible with our shield support, see #40645.

@jfischer-no Maybe you haven't noticed, but Zephyr already has different kind of board variants, both formal and informal.

Formal variant is revision.

Informal variant are those used my multi-core SoCs and secure / non-secure targets (cryptocell).

For example, the nRF5340dk_nrf5340 board comes in following variants:

  • nrf5340dk_nrf5340_netcore: variant identifying network core in the SoC
  • nrf5340dk_nrf5340_appcore: variant identifying application core in the SoC
  • nrf5340dk_nrf5340_appcore_ns: configuration variant identifying anon-secure application in the appcore in the SoC.

Now, especially ns is of interest, as it is a configuration variant, but we don't identify it using shield principle.
In which way is a cdc_acm configuration variant of a board significantly different from a ns configuration variant, or other variants mentioned above ?

This is the reason why we should formalize board variant handling in Zephyr, and have revision a specialized type of variant.
And having common baseline variant names ensures the board itself will be able to present if a given variant is supported (something the shield mechanism can never provide)

Other boards with informal variants (non-exhaustive list): lpcxpresso54114, nrf9160dk_nrf9160, mps2_an521

@jfischer-no
Copy link
Collaborator

This neither makes sense nor is it helpful to provide a generic board-wide (or tree-wide) configuration, as it is possible with our shield support, see #40645.

@jfischer-no Maybe you haven't noticed, but Zephyr already has different kind of board variants, both formal and informal.

Formal variant is revision.

Informal variant are those used my multi-core SoCs and secure / non-secure targets (cryptocell).

For example, the nRF5340dk_nrf5340 board comes in following variants:

* nrf5340dk_nrf5340_netcore: variant identifying network core in the SoC

* nrf5340dk_nrf5340_appcore: variant identifying application core in the SoC

* nrf5340dk_nrf5340_appcore_ns: configuration variant identifying anon-secure application in the appcore in the SoC.

Now, especially ns is of interest, as it is a configuration variant, but we don't identify it using shield principle. In which way is a cdc_acm configuration variant of a board significantly different from a ns configuration variant, or other variants mentioned above ?

Related to configuration and devicetree, _ns is name agreement only, it does not provide common configuration for all boards, it depends on SoC, and in that case boards have same fragments, see nrf5340dk and bl5340_dvk for example. Of course one could add absolutely the same configuration and devicetree description for all boards that have USB device support and want to use CDC ACM as backend, but that would be stupid, and not maintenance friendly, and also not solve all problems, because it is reasonable to have separate backends for logging and shell, and another one maybe for something else. In contrast, the solution based on shield support like #40645 is omnipotent, it is combinable and works for all boards that have USB device support, whether nrf52840donge or nrf52840dk, downsream and upstream.

This is the reason why we should formalize board variant handling in Zephyr, and have revision a specialized type of variant. And having common baseline variant names ensures the board itself will be able to present if a given variant is supported (something the shield mechanism can never provide)

Other boards with informal variants (non-exhaustive list): lpcxpresso54114, nrf9160dk_nrf9160, mps2_an521

@mbolivar-nordic
Copy link
Contributor

I probably do not quite understand the motivation for these changes, for my part related to #40645, I suggest to rename shield to something more generic and derive from it shield for hardware and foobar for specific configuration.

@jfischer-no I think we may all be in violent agreement here. In particular, I think that we should make sure that "snippets" have the features from "shields" that you require for #40645. Assuming that is fine for you, maybe we can proceed with that plan?

@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@mbolivar-nordic
Copy link
Contributor

@jfischer-no I think we may all be in violent agreement here. In particular, I think that we should make sure that "snippets" have the features from "shields" that you require for #40645. Assuming that is fine for you, maybe we can proceed with that plan?

ping

Jordan Yates added 4 commits July 1, 2022 21:52
Introduce the concept of snippet's to application configuration. A
snippet is a piece of functionality that is not the default behaviour
of a board, but is a common configuration that users may wish to apply.

One example snippet concept is "usb" which may route the console to USB
instead of a serial port. Another common snippet could be "mcuboot",
which would define the flash partitions required for applications to
be loaded by a bootloader.

The name "snippet" was chosen mainly to avoid collisions with existing
terms. Alternatives considered include:
 * overlay (collision with devicetree overlay concept)
 * config (collision with Kconfig)
 * part (collision with --pristine build option, flash partitions)
 * layout (implies memory configuration)

The Oxford dictionary definition of snippet appears to match this
concept well, "a small piece or brief extract".

Snippets are a required devicetree `.overlay` file, an optional `.conf`
file and an optional `.cmake` file. `.overlay` files and `.conf` files
are appended to to the existing CMake variables `DTC_OVERLAY_FILE` and
`CONF_FILE` respectively. The `.cmake` file is evaluated immediately,
which allows setting configurations before Kconfig or DTS parsing runs.

The initial search paths for these files are
`${APPLICATION_SOURCE_DIR}/boards/${BOARD}/snippets` and
`${BOARD_DIR}/snippets`, with the application directory having
precedence to allow for overriding board defaults.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
Remove the `-s` option which was deprecated 3 years ago to make
namespace for a snippet argument.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
Add a `west build` argument (`-s`, `--snippet`) for constructing the
cmake `SNIPPETS` variable.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
Temporary commit to show how existing definitions could be split under
the "snippets" paradigm. Example build commands:

```
west build -b nrf52840dk_nrf52840 samples/basic/blinky
west build -b nrf52840dk_nrf52840 samples/basic/blinky -s usb
west build -b nrf52840dk_nrf52840 samples/basic/blinky -s mb_boot
west build -b nrf52840dk_nrf52840 samples/basic/blinky -s mb_slot0
west build -b nrf52840dk_nrf52840 samples/basic/blinky -s usb -s mb_slot0
```

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
@zephyrbot zephyrbot requested review from gmarull and utzig July 1, 2022 12:05
@JordanYates
Copy link
Collaborator Author

This has been updated for v3.1 with some minor changes since I've been using snippets in my fork for a few months.
The important change is that snippets now allow an optional .cmake file to be run as well. This allows the old "separate board for nonsecure" paradigm to be removed in favour of a trivial snippet.

nonsecure.cmake

list(APPEND DTS_EXTRA_CPPFLAGS "-DARM_TRUSTZONE_NON_SECURE")

nonsecure.conf

# This snippet implies building Non-Secure firmware
CONFIG_TRUSTED_EXECUTION_NONSECURE=y

nonsecure.overlay

/ {
	chosen {
		zephyr,code-partition = &nonsecure_partition;
		zephyr,sram = &sram0_ns;
	};
}

thingy91.dtsi

#ifdef ARM_TRUSTZONE_NON_SECURE
#include <nordic/nrf9160ns_sica.dtsi>
#else
#include <nordic/nrf9160_sica.dtsi>
#endif /* ARM_TRUSTZONE_NON_SECURE */

That is sufficient to build nonsecure applications just by adding -s nonsecure, without any of the _ns files currently in the tree.

gmarull added a commit to teslabs/example-application that referenced this pull request Jul 1, 2022
-s/--source is a legacy option. There's a proposal to actually use it
for something else in Zephyr now:

zephyrproject-rtos/zephyr#40669

Let's update README.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
gmarull added a commit to teslabs/example-application that referenced this pull request Jul 1, 2022
-s/--source is a legacy option. There's a proposal to actually use it
for something else in Zephyr now:

zephyrproject-rtos/zephyr#40669

Let's update README.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
Copy link
Member

@gmarull gmarull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I like the idea, and not against the name, so +1 from my side.

carlescufi pushed a commit to zephyrproject-rtos/example-application that referenced this pull request Jul 7, 2022
-s/--source is a legacy option. There's a proposal to actually use it
for something else in Zephyr now:

zephyrproject-rtos/zephyr#40669

Let's update README.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Aug 31, 2022
@github-actions github-actions bot closed this Sep 15, 2022
@mbolivar-nordic mbolivar-nordic mentioned this pull request Nov 1, 2022
a-v-s pushed a commit to BlaatSchaapCode/party_hat_zephyr that referenced this pull request Jun 23, 2024
app: initial application skeleton

initial application skeleton demonstrating:

- custom boards
- custom DT bindings
- Out-of-tree drivers

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: initial CI example

CI example using Github Actions

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

app: provide in-tree board overlay

Provide an overlay to shows how to run the example-application on boards
that are part of the Zephyr tree. Sometimes initial development is
performed on dev-kits, so it can be useful. A different vendor than the
one used for the custom board (Nordic) has been chosen to show
application portability.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

readme: add more details on board usage

Inform about the possibility of using Zephyr sample boards.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

readme: remove doc from list of features

Documentation is not (yet) provided.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

drivers: sensor: examplesensor: use GPIO_DT_SPEC_INST_GET

Instance version of the GPIO_DT_SPEC_GET was recently introduced.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: run on pull_request

Run CI on push and pull_request.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

manifest: use Zephyr main branch

Zephyr now uses main instead of master.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: Remove cache

CI is failing and it seems related to cache.  Remove for now to get
CI passing again.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>

readme: add versioning scheme information

Mention that example-application follow Zephyr version scheme.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

manifest: pin to Zephyr v2.6.0

Pin to Zephyr v2.6.0 for the v2.6.0 release of the example-application.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

manifest: Switch back to main after release

Switch back to pointing to main after the v2.6.0 release.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

drivers: sensor: examplesensor: use gpio_pin_get_dt

Use the recently introduced GPIO API that allows obtaining pin state
using the gpio_dt_spec struct.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

app: delete foo sample code

The initial idea behind this code was to showcase documentation. It does
not add any special value to the sample, so remove it. A proper library
can be added in the future.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

workflow: add /opt/toolchains to CMAKE_PREFIX_PATH in environment.

Fixes: #39270

The latest zephyrprojectrtos/ci no longer sets ZEPHYR_SDK_INSTALL_DIR
in the environment and doesn't register the Zephyr-SDK as a CMake
package in the CMake package registry.

To ensure the the Zephyr SDK can be correctly discovered by
find_package(Zephyr-sdk) we add `/opt/toolchains` to the
CMAKE_PREFIX_PATH environment variable which is a list containing
additional search prefixes for the `find_package()` function.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>

manifest: pin to Zephyr v2.7.0

Pin to Zephyr v2.7.0 for the v2.7.0 release of the example-application.

Signed-off-by: Christopher Friedt <chrisfriedt@gmail.com>

manifest: Switch back to main after release

Switch back to pointing to main after the v2.7.0 release.

Signed-off-by: Christopher Friedt <chrisfriedt@gmail.com>

app: use <kernel.h> include

<zephyr.h> is a proxy to <kernel.h> in practice, so let's use <kernel.h>
instead.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

app, drivers: migrate includes to <zephyr/...>

Zephyr includes are now prefixed with <zephyr/...>. While the old path
can still be used when CONFIG_LEGACY_INCLUDE_PATH=y, it's better to be
prepared for the future.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

west: Pin the Zephyr release to v3.1.0

Align with Zephyr relase v3.1.0.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

west: Point back to main after release

After releasing v3.1.0, move back to main.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

ci/readme: remove usage of -s legacy option

-s/--source is a legacy option. There's a proposal to actually use it
for something else in Zephyr now:

zephyrproject-rtos/zephyr#40669

Let's update README.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

readme: Add links to app dev and west

Link to the relevant sections in the Zephyr documentation, including
application development and west topologies.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

drivers: sensor: examplesensor: use DT_HAS_* helper

Make zephyr,examplesensor driver option dependent on it being defined in
Kconfig and set its default based on DT status as well.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

app: remove redundant CONFIG_EXAMPLESENSOR in prj.conf

The option is no longer needed, zephyr,examplesensor driver will
automatically be selected based on DT (and because we enable all of its
dependencies, including CONFIG_SENSOR).

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

devicetree: remove usage of deprecated label property

Devicetree label property has been deprecated, so remove its usage.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

drivers: sensor: examplesensor: use select in Kconfig

With the recent changes in how Kconfig options are enabled using DT
helpers, using select leads to a better/more scalable pattern. Each
driver Kconfig option is expected to select its dependencies now.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

west: add example west command

Add a working example for how to implement a west command within the
user's manifest repository. There is documentation for this, but we
should have some working code in here just to make life easier for
people.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>

west: Pin the Zephyr release to v3.2.0

Align with Zephyr relase v3.2.0.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

west: Point back to main after release

After releasing v3.2.0, move back to main.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

lib: create empty lib subsystem

Create lib subsystem with empty Kconfig menu, subsystem build file.
Updated top-level build and documentation to include subsystem.
This was created to provide an example of how the `lib/` directory
can be connected to the Zephyr build system through `module.yml`,
and so that CI can verify that the extension settings used here
work with these sub-trees.
.
The approach follows the pattern of paralleling the Zephyr tree.
An empty subsystem was implemented rather than a non-empty one
in order to isolate the core changes from any specific library.
This provides a clean reference for users.
.
It was assumed that some users will want to strip out the `lib/`
subsystem separate from existing subsystems, and vice versa.
.
This was verified by:
  - visually verifying a clean build of:
      `west build -b custom_plank -p always example-application/app/`
  - visually verifying the subsystem appeared in the correct
    location in a clean build of:
      `west build -b custom_plank -p always example-application/app/`

Signed-off-by: Gregory Shue <gregory.shue@legrand.us>

lib: add custom_lib

Enhance the example-application repository with a configurable,
trivial library example and associated test cases.
.
This implementation appears to make no assumptions.
.
This implementation was verified by running the following commands
in an example-application workspace and verifying all tests passed.
  1. `west build -b native_posix -p always example-application/tests/lib/custom_lib/`
  2. `./build/zephyr/zephyr.exe`
  3. `west build -b native_posix -p always example-application/tests/lib/custom_lib/ -- -DCONFIG_CUSTOM_LIB_GET_VALUE_DEFAULT=6`
  4. `./build/zephyr/zephyr.exe`
  5. `zephyr/scripts/twister -T example-application/tests/ \
      -p qemu_cortex_m0`
  6. `cd zephyr/doc && make clean && make` built cleanly.
.
Note that `twister` does not follow the `zephyr/module.yml:tests`
setting to discover tests in modules, so the testcase-root must be
explicitly provided.

Fixes #35177

Signed-off-by: Gregory Shue <gregory.shue@legrand.us>

boards: custom_plank: migrate to pinctrl

The board still used deprecated nRF *-pin properties,
migrate it to pinctrl.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

workflows: build: Do not install west and requirements

This is not necessary since it's running in the zephyr docker image,
that already contains them.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

lib: Remove trailing whitespace

We need a compliance check.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

tests: custom_lib: Fix include paths

Align to the new standard that prefixes zephyr/.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

tests: custom_lib: port to the new ztest API

Align with the latest upstream API.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

lib: Fix running twister

Use integration_platforms and invoke twister properly.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

tests: lib: custom_lib: require CMake 3.20

Zephyr now requires CMake >= 3.20.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

tests: lib: custom_lib: use YAML empty dictionary syntax

There is no need to use dummy properties when an empty dictionary
can be used.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

tests: lib: custom_lib: fix includes

Test was including Kernel for nothing, and missed limits.h
(likely included by Kernel)

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

doc: cleaning up the readme.md

Cleaning up the language and formatting in the
README.md document file.

Signed-off-by: Pekka Niskanen <pekka.niskanen@nordicsemi.no>

west.yml: remove 'self: path:'

This makes it easier to rename this repository and use it under its
new name. For example, with this patch, if you push the repository to
GitHub user 'foo' as repository 'bar', you can do:

  west init -m https://github.com/foo/bar my-workspace

And you will get:

  - my-workspace/.west/config says manifest.path is 'bar'
  - my-workspace/bar exists as a git repository

By contrast, with the current 'self: path:' setting, you will instead
get:

  - my-workspace/.west/config says manifest.path is
    'example-application'
  - my-workspace/example-application exists as a git
    repository

Let's let people name this repository whatever they want, and get the
expected results, instead of forcing the name example-application

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>

west: Pin the Zephyr release to v3.3.0

This commit pins the example-application to the Zephyr release v3.3.0.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>

west: Point back to main after 3.3.0 release

This commit updates the example-application to point back to the Zephyr
main branch after the Zephyr v3.3.0 release.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>

app: adjust main definition

Zephyr now requires `int main(void)`. Main must return 0, all other
values are reserved.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: schedule a daily build

Schedule a daily build, so that we can quickly spot regressions in the
application due to changes in Zephyr.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

readme: Mention Zephyr modules

This repo also demonstrates Zephyr modules, since it's a module itself.
Add a link to the list of features.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>

ci: build: update checkout/upload-artifact actions

These actions are triggering warnings about usage of deprecated features
(e.g. NodeJS 12). Use latest version of the actions.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

gitignore: add twister folders

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: remove redundant --board-root

Twister automatically adds module board root folders now.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: use west twister

Invoke Twister using west.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: simplify twister args

s/G/--integration (more clear)
s/--testsuite-root/-T (shorter, still clear)

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

manifest: only clone required modules

Optimize setup/CI time by cloning only what is necessary.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: pin runner and container versions

Make sure we can safely go back in time by pinning runner and container
versions.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: do not archive firmware

It's not useful, just wastes time/space for nothing.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

boards: custom_plank: add missing CONFIG_PINCTRL=y

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

app: remove rtt config

RTT is something proprietary, not all boards/programmers have. Let's
make the application simpler.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

app: add sample.yaml

Add a sample.yaml so that we can use twister to compile the application
in CI.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

ci: build application using twister

Twister is more useful in a CI context because we can easily test
multiple combinations of the firmware using a single command.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

app: use extra_overlay_confs

Using OVERLAY_CONFIG in extra_args is deprecated in favor of
extra_overlay_confs.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

version: Replace bespoke application version with new version system

Uses Zephyr's new version infrastruction system for configuring the
version of the application and displaying it.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>

ci: use shallow fetch and no tags

Add a couple flags to west update to do shallow fetch for both the main
repo and modules, and don't fetch any tags. Should speed things up a bit
by only fetching the target version code for all modules.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

Documentation: Add Twister Integration tests instructions

Added Twister Integration tests instructions to the README.md file.

Signed-off-by: Ivan Vnucec <vnucec.ivan@gmail.com>

west: Pin the Zephyr release to v3.5.0

Align with Zephyr relase v3.5.0.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

west: Point back to main after release

After releasing v3.5.0, move back to main.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

tests: drop CONFIG_ZTEST_NEW_API

This is now gone from upstream and not needed anymore.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

boards: custom_plank: use gpio-as-nreset instead of CONFIG_GPIO_AS_PINRESET

CONFIG_GPIO_AS_PINRESET is deprecated, replace it with the new device
tree property.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

boards: custom_plank: enable gpiote

The gpiote node has to be enabled for the board to build since the
latest upstream nrfx hal update.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

ci: use the zephyr-setup action

Use the standard generic GitHub images for the run and the zephyr-setup
action, run the build on both Linux, macOS and Windows.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

ci: align the runner list with the main repository

Use the same runner list as the main repository ones. Originally I meant
to just add macos-14 so we cover macOS ARM, which is nice because it
runs on qemu-m0 from the brew package, but at this point let's also use
explicit version for the other runners too.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>

west: Pin the Zephyr revision to v3.6.0

Pins the Zephyr revision to the latest release, v3.6.0.

Signed-off-by: Maureen Helm <maureen.helm@analog.com>

west: Point Zephyr back to main after v3.6.0 release

Points the Zephyr revision back to the main branch after the latest
release, v3.6.0.

Signed-off-by: Maureen Helm <maureen.helm@analog.com>

boards: custom_plank: port to HWMv2

Port the custom_plank example out-of-tree board to HWMv2.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

readme: Added missing directory change in build instructions

The current build instructions omit a necessary directory
change after creating the workspace.

Signed-off-by: Andy Sinclair <andy.sinclair@nordicsemi.no>

include: namespace includes with app/ prefix

All example-application level includes will have the 'app' prefix,
making ownership obvious and reducing the chances of namespacing
clashes. This aligns with how Zephyr works with the 'zephyr' prefix.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

lib: custom: simplify naming scheme

Improve the naming scheme of the custom library.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

boards: custom_plank: tweak defconfig with UART console

To improve the default user experience. However, explain this may not be
the best choice on production boards.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

drivers: sensor: s/examplesensor/example-|_sensor/

Just a rename so things look a bit nicer.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

drivers: blink: add custom out-of-tree driver class

Add a new out-of-tree custom driver class to demonstrate all aspects of
custom driver class creation.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

drivers: blink: blink-gpio-led: add initial implementation

Add a blink driver implementation for a GPIO-controlled LED.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

boards: custom_plank: instantiate blink-gpio-led

Define an instance of a blink-gpio-led. Since custom_plank is in reality
a nRF52840DK, this uses LED0 as the blink-gpio-led.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

app: boards: nucleo_f302r8: instantiate blink-gpio-led

Instantiate blink-gpio-led (uses board Green LED).

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

app: update application to use the custom blink API

Update the application to use the new custom blink API. It changes the
blink period if the sensor reports a proximity value that is 1.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: add Doxygen configuration

Add a simple Doxygen configuration that allows to build documentation
for the application APIs found under include/.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: add minimal Sphinx setup

Add a minimal Sphinx-based setup, also configuring intersphinx for
Zephyr.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

ci: add workflow to build and publish docs

Add a workflow that, for now, builds Doxygen docs and published them on
Github pages.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

readme: add documentation details

Inform the users on how to quickly build the documentation.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

cmake: use zephyr_syscall_include_directories

Instead of appending to SYSCALL_INCLUDE_DIRS.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

readme: swap doxygen/sphinx badges

Prefer Sphinx as the first entry.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: add breathe and import existing Doxygen groups

In Zephyr, most APIs in Doxygen are also imported in Sphinx using the
breathe exstension. While breathe is de-facto unmaintained, this comes
handy to have an integrated documentation experience. User is warned to
check the maintainership status of breathe, because Doxygen in
standalone mode (also offered) may be enough.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: move Zephyr references to standalone page

So that home page is de-cluttered.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: remove sphinx-quickstart redundant comments

These are not useful.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

ci: deploy Sphinx content to the root folder

Prefer Sphinx content as the landing page, specially now that it
contains API docs as well.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>

doc: Typo fix

Typo fix in ReadMe file

Signed-off-by: UMA PRASEEDA <uma.praseeda@nordicsemi.no>

boards: custom_plank: remove redundant PINCTRL defconfig

Drivers using pinctrl already select this option.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.