Skip to content

Conversation

@chrysn
Copy link
Member

@chrysn chrysn commented May 6, 2025

Contribution description

The nrfutil programmer used for nrf52840dongle was never FLOSS (AFAICT it always had a 3-clause BSD license plus but-only-use-it-for-our-hardware), and installation has become way more convoluted since they abandoned the Python version.

There is a free implementation that's generally more hassle-free, too, as it works right from the .elf without going the extra detour over a programmer-specific zip file. [edit:] It is set as the new default.

Testing procedure

While there has not been a new release of nrfdfu: cargo install --git https://github.com/knurling-rs/nrfdfu-rs/ (later it should be cargo install nrfdfu)

  • Take any test or example and run make -C tests/periph/cpuid BOARD=nrf52840dongle all flash term. (No need to set PROGRAMMER=nrfdfu -- it is the default now).

Note that unlike nrfutil, this tool discards the PORT= variable -- it doesn't deal in serial port terms, it looks at USB devices with the right uid/vid; there's a PR to identify the USB device through its serial number, which IMO should be the way to go for us anyway.

Issues/PRs references

@chrysn chrysn requested a review from aabadie as a code owner May 6, 2025 12:41
@chrysn chrysn added Area: build system Area: Build system Area: boards Area: Board ports labels May 6, 2025
@github-actions github-actions bot added Area: doc Area: Documentation and removed Area: build system Area: Build system labels May 6, 2025
@crasbe crasbe added Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels May 6, 2025
@riot-ci
Copy link

riot-ci commented May 6, 2025

Murdock results

✔️ PASSED

11e54b0 boards/nrf52840dongle: Documentation precision for nrfutil

Success Failures Total Runtime
589 0 589 05m:27s

Artifacts

@chrysn chrysn marked this pull request as draft May 6, 2025 17:21
@chrysn chrysn requested a review from Ollrogge May 6, 2025 17:21
@crasbe
Copy link
Contributor

crasbe commented May 6, 2025

I wonder if it wouldn't be nice to include a dist/tools script similar to dist/tools/uf2 or dist/tools/picotool, so that the user does not have to deal with installing the flasher.

That script should include a check if cargo is installed in order to avoid weird errors.

FLASHFILE = $(HEXFILE)
FLASHDEPS += $(HEXFILE).zip
FLASHER = nrfutil
FFLAGS = dfu usb-serial --port=${PORT} --package=$(HEXFILE).zip
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
FFLAGS = dfu usb-serial --port=${PORT} --package=$(HEXFILE).zip
FFLAGS = dfu usb-serial --port=$(PORT) --package=$(HEXFILE).zip

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd rather leave it as is in this commit so that it is visible in the commit that this line was not modified. (The GitHub diff settings choice mark it as a new line, but eg. a git diff color-moved does show those as unmodified).

FFLAGS = $(FLASHFILE)
endif

ifeq (1,$(USING_NRF_BOOTLOADER))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifeq (1,$(USING_NRF_BOOTLOADER))
ifneq (,$(filter nrfutil nrfdfu,$(PROGARMMER)))

Since the number of programmer variants is very limited (two), we could omit the extra variable here.
NRF_BOOTLOADER might be misleading, since there is (at least) one other bootloader for the nRFs, the Adafruit nRF52 Bootloader.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think there is value to having this independent, because it could also be used with an external programmer but leaving the bootloader in place.

Even if you accept that rationale, let's leave this open for the naming issue. I think that the adafruit bootloader is similar enough, but I'll want to check that anyway while looking at knurling-rs/nrfdfu-rs#16, and then I'll see if there is a better name to use here.

Copy link
Contributor

Choose a reason for hiding this comment

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

That is a valid point, but then the parameter must be documented somewhere.

There is a similar parameter for the Adafruit nRF52 Bootloader called UF2_SOFTDEV to keep the SoftDevice in place. However that wouldn't protect the Bootloader from overriding with a JLink.

@@ -1,31 +1,41 @@
# This board uses the vendor's serial bootloader

PROGRAMMER ?= nrfutil
Copy link
Contributor

Choose a reason for hiding this comment

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

I think if nrfdfu works well, we could set it as default too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, why not! It is consistent with our preference for FLOSS tools.

@Ollrogge
Copy link
Member

Ollrogge commented May 7, 2025

Successfully tested on my nrf52840dongle. Output:

nrfdfu /home/nils/Programming/RIOT/tests/periph/cpuid/bin/nrf52840dongle/tests_cpuid.elf
[INFO  nrfdfu] Sending init packet...
[INFO  nrfdfu] Sending firmware image of size 16776...
[INFO  nrfdfu] Done.
sleep 2
/home/nils/Programming/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "115200" -ln "/tmp/pyterm-nils" -rn "2025-05-07_10.14.54-tests_cpuid-nrf52840dongle"
Twisted not available, please install it if you want to use pyterm's JSON capabilities
2025-05-07 10:14:54,278 # Connect to serial port /dev/ttyACM0
Welcome to pyterm!
Type '/exit' to exit.
2025-05-07 10:14:55,282 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,283 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,284 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,284 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,285 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,286 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,286 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,286 # READY
2025-05-07 10:14:55,287 # Help: Press s to start test, r to print it is ready
2025-05-07 10:14:55,287 # START
2025-05-07 10:14:55,287 # main(): This is RIOT! (Version: 2025.07-devel-136-gcab6f-HEAD)
2025-05-07 10:14:55,287 # Test for the CPUID driver
2025-05-07 10:14:55,287 # This test is reading out the CPUID of the platforms CPU
2025-05-07 10:14:55,287 #
2025-05-07 10:14:55,287 # CPUID_LEN: 8
2025-05-07 10:14:55,288 # CPUID: 0xfe 0xf4 0xfc 0x4e 0xe7 0x55 0x40 0xc0
2025-05-07 10:14:55,288 # { "threads": [{ "name": "main", "stack_size": 1536, "stack_used": 460}]}
2025-05-07 10:14:57,077 # Exiting Pyterm

@chrysn
Copy link
Member Author

chrysn commented May 7, 2025

I wonder if it wouldn't be nice to include a dist/tools script similar to dist/tools/uf2 or dist/tools/picotool, so that the user does not have to deal with installing the flasher.

The makefiles currently do test for whether the flasher is installed, but only give a generic error message.

As for auto-adding, I'm a bit unsure. Our general approach there is highly inconsistent (some tools have a pkg and auto-build, some just expect things to be there, and there is the idea floating on chat but not in an issue yet to make every Python thing with dependencies just run pipx run). Until we clean that up, I'd rather not come up with a new approach on the side here.

Also, I wouldn't know how to best do it: cargo install installs into a user-wide place in $PATH and I don't think RIOT should do that; if cargo-install can be told to put the binary somewhere inside the RIOT checkout, that'd be fine (and then run with --no-track to avoid cargo remembering it in its user-wide directories), but the only way I know to change that is to change CARGO_PATH, and then all of a sudden we don't use the (desirable) global download cache and settings any more.

@crasbe
Copy link
Contributor

crasbe commented May 7, 2025

Also, I wouldn't know how to best do it: cargo install installs into a user-wide place in $PATH and I don't think RIOT should do that; if cargo-install can be told to put the binary somewhere inside the RIOT checkout, that'd be fine (and then run with --no-track to avoid cargo remembering it in its user-wide directories), but the only way I know to change that is to change CARGO_PATH, and then all of a sudden we don't use the (desirable) global download cache and settings any more.

Disclaimer: I'm completely unfamiliar with Rust (at least the Programming Language, I got some experience dealing with rusty metal) and Cargo, but the documentation says there is the --root option, which specifies the installation directory and is preferred over the CARGO_PATH.
Also the metadata that Cargo saves to keep track about installed files is apparantely stored in that root directory.

So it should just work with --root? I guess?

@crasbe
Copy link
Contributor

crasbe commented May 7, 2025

### nRF52
- `adafruit-nrfutil` (requires Adafruit bootloader)
- `nrfutil` (required nRF bootloader)

This paragraph has to be updated as well with this PR.

@Ollrogge
Copy link
Member

@chrysn what is the reason for this still being a draft ?

@chrysn
Copy link
Member Author

chrysn commented May 14, 2025

Mainly that I'd hope for a nrfdfu release soonish so we don't tell people to cargo install --git https://github.com/so/mething but just cargo install something.

(But I could probably just declare that a secondary issue, address the review comments and make it ready -- just can't do that right now)

@crasbe
Copy link
Contributor

crasbe commented May 14, 2025

Mainly that I'd hope for a nrfdfu release soonish so we don't tell people to cargo install --git https://github.com/so/mething but just cargo install something.

You know what would solve that? A Makefile in dist/tools that specifies the hash for Cargo 👀 🤣

@chrysn
Copy link
Member Author

chrysn commented May 14, 2025

You know what would solve that? A Makefile in dist/tools that specifies the hash for Cargo 👀 🤣

No it wouldn't: Unless we go through our own local installations unconditionally and never use locally installed tools (and I'm rather confident people don't want that -- most of RIOT development works from a plain git checkout with just distro-provided software), installations would fail with hard-to-debug errors for people who already have the latest version of the tool installed.

Be my guest to come up with an elaborate scheme to run installed tools to probe for their version number, fall back to the tools we autobundle, and sensibly cache all that information so CI runs don't grind to a halt from all the auto-testing, but that level of complexity has no place in this PR.

@crasbe
Copy link
Contributor

crasbe commented May 14, 2025

No it wouldn't: Unless we go through our own local installations unconditionally and never use locally installed tools (and I'm rather confident people don't want that -- most of RIOT development works from a plain git checkout with just distro-provided software), installations would fail with hard-to-debug errors for people who already have the latest version of the tool installed.

That is not true for all tools. The aforementioned picotool for example is always fetched from remote.
I'm not sure though if the normal CI processes actually execute any of the flash targets?

Be my guest to come up with an elaborate scheme to run installed tools to probe for their version number, fall back to the tools we autobundle, and sensibly cache all that information so CI runs don't grind to a halt from all the auto-testing, but that level of complexity has no place in this PR.

Who could deny an invitation like that? :)

PKG_NAME       := nrfdfu
PKG_URL        := https://github.com/knurling-rs/nrfdfu-rs.git
PKG_VERSION    := 6ec635d1f2bef827c8029832a384283c057f9698
PKG_LICENSE    := MIT
PKG_BUILD_DIR  := build

REMOTE_CARGO_TOML_RAW_URL := https://raw.githubusercontent.com/knurling-rs/nrfdfu-rs/$(PKG_VERSION)/Cargo.toml

# make sure Cargo is installed
CARGO_EXISTS := $(shell command -v cargo 2>/dev/null)

ifeq (,$(CARGO_EXISTS))
  $(error 'cargo' is not installed or not in PATH)
endif

# parse the Cargo.toml file to get the version of the nrfdfu util
REMOTE_VER := $(shell curl -sSL $(REMOTE_CARGO_TOML_RAW_URL) | grep '^version' | head -n1 | sed 's/version *= *"\(.*\)"/\1/')

GLOBAL_VER_TMP := $(shell \
  cargo install --list 2>/dev/null | grep "^$(PKG_NAME) v" | sed -E 's/.*v([0-9.]+).*/\1/' )

# a version number may or may not have a URL at the end
GLOBAL_VER = $(firstword $(GLOBAL_VER_TMP))

LOCAL_VER_TMP := $(shell \
  cargo install --root $(PKG_BUILD_DIR) --list 2>/dev/null | grep "^$(PKG_NAME) v" | sed -E 's/.*v([0-9.]+).*/\1/' )

LOCAL_VER = $(firstword $(LOCAL_VER_TMP))


# Installation Decision Tree
# Note: it is up to the user to run `make clean` from time to time to remove
# old installations. It is assumed that the local installation is newer than
# the global installation and therefore preferred if present.

INSTALL_TARGET=

ifneq (,$(GLOBAL_VER))
  # check if there is a global installation
  ifeq ($(GLOBAL_VER),$(REMOTE_VER))
    # check if the global and remote installation have the same version
    ifeq (,$(LOCAL_VER))
      # create a symlink to the global installation if no local
      # installation is present
      INSTALL_TARGET = link
      $(info [INFO] Using global nrfdfu util...)
    endif
  else
    # it is unlikely that the global installation is newer than the remote
    # version, therefore install the remote version.
    ifeq (,$(LOCAL_VER))
      INSTALL_TARGET = local
    endif
  endif
else
  ifeq (,$(LOCAL_VER))
    # no local installation present
    INSTALL_TARGET = local
    $(info [INFO] No nrfdfu util found...)
  endif
endif

$(CURDIR)/nrfdfu: $(INSTALL_TARGET)

.PHONY: local link clean distclean

local:
        @echo "[INFO] Installing $(PKG_NAME) ($(REMOTE_VER)) from Git repo..."
        @cargo install --root $(PKG_BUILD_DIR) --git $(PKG_URL) --rev $(PKG_VERSION) --quiet
        @cp $(PKG_BUILD_DIR)/bin/nrfdfu .
        @chmod a+x nrfdfu

link:
        @echo "[INFO] Creating a symlink for nrfdfu..."
        @ln -s ~/.cargo/bin/nrfdfu nrfdfu

clean::
        @rm -rf nrfdfu

distclean:: clean
        @rm -rf $(PKG_BUILD_DIR)

Option 1: cargo not installed:

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ make
Makefile:13: *** 'cargo' is not installed or not in PATH.  Stop.

Option 2: No nrfdfu installed:

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ make
[INFO] No nrfdfu util found...
[INFO] Installing nrfdfu (0.1.3) from Git repo...
warning: fields `part`, `variant`, `rom_size`, `ram_size`, and `rom_page_size` are never read
   --> src/messages.rs:181:5
    |
179 | pub struct HardwareVersionResponse {
    |            ----------------------- fields in this struct
180 |     // See FICR register docs
181 |     part: u32,
    |     ^^^^
182 |     variant: u32,
    |     ^^^^^^^
183 |     rom_size: u32,
    |     ^^^^^^^^
184 |     ram_size: u32,
    |     ^^^^^^^^
185 |     rom_page_size: u32,
    |     ^^^^^^^^^^^^^
    |
    = note: `HardwareVersionResponse` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
    = note: `#[warn(dead_code)]` on by default

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ ls -l
total 13424
-rw-r--r-- 1 cbuec cbuec     2541 May 14 15:12 Makefile
drwxr-xr-x 3 cbuec cbuec     4096 May 14 15:13 build
-rwxr-xr-x 1 cbuec cbuec 13735360 May 14 15:13 nrfdfu

Option 3: nrfdfu installed globally, same version as remote:

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ cargo install nrfdfu
    Updating crates.io index
  Installing nrfdfu v0.1.3
    Updating crates.io index
...
   Compiling nrfdfu v0.1.3
    Finished release [optimized] target(s) in 7.87s
  Installing /home/cbuec/.cargo/bin/nrfdfu
   Installed package `nrfdfu v0.1.3` (executable `nrfdfu`)
warning: be sure to add `/home/cbuec/.cargo/bin` to your PATH to be able to run the installed binaries
cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ make
[INFO] Using global nrfdfu util...
[INFO] Creating a symlink for nrfdfu...
cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ ls -l
total 12
-rw-r--r-- 1 cbuec cbuec 2538 May 14 15:10 Makefile
drwxr-xr-x 2 cbuec cbuec 4096 May 14 15:10 build
lrwxrwxrwx 1 cbuec cbuec   29 May 14 15:10 nrfdfu -> /home/cbuec/.cargo/bin/nrfdfu

Option 4: nrfdfu installed globally, older version than remote:

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ cargo install [email protected]
    Updating crates.io index
  Installing nrfdfu v0.1.2
    Updating crates.io index
...
   Compiling nrfdfu v0.1.2
    Finished release [optimized] target(s) in 7.42s
  Installing /home/cbuec/.cargo/bin/nrfdfu
   Installed package `nrfdfu v0.1.2` (executable `nrfdfu`)
warning: be sure to add `/home/cbuec/.cargo/bin` to your PATH to be able to run the installed binaries
cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ make
[INFO] Installing nrfdfu (0.1.3) from Git repo...
warning: fields `part`, `variant`, `rom_size`, `ram_size`, and `rom_page_size` are never read
   --> src/messages.rs:181:5
    |
179 | pub struct HardwareVersionResponse {
    |            ----------------------- fields in this struct
180 |     // See FICR register docs
181 |     part: u32,
    |     ^^^^
182 |     variant: u32,
    |     ^^^^^^^
183 |     rom_size: u32,
    |     ^^^^^^^^
184 |     ram_size: u32,
    |     ^^^^^^^^
185 |     rom_page_size: u32,
    |     ^^^^^^^^^^^^^
    |
    = note: `HardwareVersionResponse` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
    = note: `#[warn(dead_code)]` on by default

cbuec@W11nMate:~/RIOTstuff/riot-gettingstarted/RIOT/dist/tools/nrfdfu$ ls -l
total 13424
-rw-r--r-- 1 cbuec cbuec     2541 May 14 15:12 Makefile
drwxr-xr-x 3 cbuec cbuec     4096 May 14 15:15 build
-rwxr-xr-x 1 cbuec cbuec 13735360 May 14 15:15 nrfdfu

The only "downside" of this solution is that apparently nrfdfu does not update the upstream version number. Even on the master branch it is the same as the release version number. But that would be a thing to be patched in the nrfdfu repository.

Also idk how to keep cargo from printing the warning messages, but they should be fixed upstream in the nrfdfu repository as well.

the bootloader.
If some other firmware is running or RIOT crashed, you need to enter the bootloader
manually by pressing the board's reset button.
#### nrfdfu
Copy link
Contributor

Choose a reason for hiding this comment

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

This paragraph should also mention that cargo, libudev-dev and pkg-build are mandatory dependencies that have to be installed first with the distribution's package manager.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not any more 🎉: The upcoming 0.2.0 release (which I'm waiting for before rebasing/fixing this all) has a change in that does away with all host dependencies but cargo, and cargo is already a build dependency of RIOT (even when not developing in Rust: some boards have Rust based RIOT modules on by default).

@chrysn
Copy link
Member Author

chrysn commented May 14, 2025

That is not true for all tools. The aforementioned picotool for example is always fetched from remote.

It is true for the tools I've worked with, but you're right, it's a bit of wild west with tools.

I'm not sure though if the normal CI processes actually execute any of the flash targets?

No, but re/ wild west, I think we should aspire to use a single mechanism for the tools we need no matter whether they're part of the flashing process or of the building process.

Who could deny an invitation like that? :)

I was about to quote a movie, but given that 1990s movies' language isn't suitable here, I'll post a picture that shows that indeed I'm both happy and impressed:

gold1

I'll have some review comments (in particular, I think that if we go with a tag rather than a hash, or the version in addition, we might avoid pulling all the source for nothing if the local package is installed -- and given we have a bad habit of copy-pasting, it might already be a good time to pull out the bulk into an included "this is a Rust tool" generic Makefile), but it looks quite cool already. do you have that code as a branch somewhere, or can I craft a commit with that content and you as the author?

Re. upstream, they're already active fixing the warnings. The version they advertise in their Cargo.toml is at least consistent with common practice of only altering the Cargo.toml version before a release -- personally I prefer having it 1.2.3 at the tagged version and 1.2.4-alpha.0 or something like that right after the release, but that's a lot of back-and-forth commits (and Rust doesn't have too much flexibility in what is in a version).

@crasbe
Copy link
Contributor

crasbe commented May 14, 2025

I'll have some review comments (in particular, I think that if we go with a tag rather than a hash, or the version in addition, we might avoid pulling all the source for nothing if the local package is installed

The Makefile is not totally up to standard, it does not use the pkg/pkg.mk Makefile because that would always pull the sources from Github.

-- and given we have a bad habit of copy-pasting, it might already be a good time to pull out the bulk into an included "this is a Rust tool" generic Makefile), but it looks quite cool already.

That is part of something I had in mind lately. Many times, the pkg/pkg.mk Makefiles creates more hurdles than help, especially if the tool does not follow the simple "git clone && make" pattern.
It would be good to have like a pkg/pkg_make.mk, pkg/pkg_cmake.mk, pkg/pkg_rust.mk, ... or pkg/pkg_custom.mk that enables maximum flexibility.
But that's a whole different can of worms.

do you have that code as a branch somewhere, or can I craft a commit with that content and you as the author?

It's not in a branch, I just made it locally. You can craft a commit.
Also it is not super polished yet, but I expected that some changes are still necessary.

Re. upstream, they're already active fixing the warnings. The version they advertise in their Cargo.toml is at least consistent with common practice of only altering the Cargo.toml version before a release -- personally I prefer having it 1.2.3 at the tagged version and 1.2.4-alpha.0 or something like that right after the release, but that's a lot of back-and-forth commits (and Rust doesn't have too much flexibility in what is in a version).

Okay, I don't know how Rust typically does it. Doxygen for example bumps the version number after a release, so that the master branch has a newer version than the last release, which is convenient for version checks such as this.

Of couse there would be a million cornercases like someone installed the current master version globally etc, but realistically, the Makefile covers most of the common cases and avoids unncecessary reinstalls.

@Ollrogge
Copy link
Member

@crasbe isn't your decision tree missing the case where there is no global installation and the local version is older than the remote version ?

@crasbe
Copy link
Contributor

crasbe commented May 15, 2025

@crasbe isn't your decision tree missing the case where there is no global installation and the local version is older than the remote version ?

Yes and no. Checks for that would make the decision tree much more compilated and IMO the user/developer can do a make clean or make distclean from time to time to get the latest versions. I don't think other packages check for updates either.

@chrysn
Copy link
Member Author

chrysn commented May 15, 2025

This is becoming the very discussion I hoped to not have in a PR that is just about replacing one bootloading-tool-the-user-has-to-install with another bootloading-tool-the-user-has-to-install.

Can we complete this with a (properly updated to list installation requirements) plain tool replacement, and move the full maintenance of on-demand install tools into a follow-up PR? (Happy to review that one, but we're now mixing very separate concerns in one thread.)

@crasbe
Copy link
Contributor

crasbe commented May 15, 2025

Sure. Let me know when this PR is ready for final review.

@chrysn
Copy link
Member Author

chrysn commented May 20, 2025

This is now ready @crasbe: to let it pass CI, I had to rebase onto main due to conflicts from #21395 -- actually, doing something similar as there might be nice, but right now we don't have any other boards supported by this bootloader, so that refactoring would likely be excessive.

@chrysn chrysn marked this pull request as ready for review May 20, 2025 13:57
@chrysn chrysn requested a review from jia200x as a code owner May 20, 2025 13:57
Comment on lines +83 to +85
When building a program for this board to be flashed using other methods
(e.g. using the board's Tag-Connect footprint),
setting `USING_NRF_BOOTLOADER=1` in the makefiles aligns the program suitable to be flashed after the bootloader.
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it make sense to set USING_NRF_BOOTLOADER ?= 1 by default and just write something like "if you want to override the original bootloader with external tools, set it to zero.
Warning: you will not be able to program the dogle without external tools anymore. You will have to reflash the original bootloader afterwards."

Copy link
Member Author

Choose a reason for hiding this comment

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

One has to use an external programmer to lock oneself out, but then I think that working on the full device unless something else is specified is at least consistent with what we had and have in other places.

There are multiple bootloaders, and people do flash other bootloaders in, so I'd say that once a debugger is connected, it's a stretch to assume that the bootloader is still there.

What I would appreciate if we had was a way to say "hey I have this board and a debugger attached, RIOT please undo what you did and do a factory reset", and I'm starting to gather the metadata for that, but that's something bigger.

Copy link
Contributor

@crasbe crasbe May 20, 2025

Choose a reason for hiding this comment

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

One should assume that when someone gathers a J-Link and a Tag Connect, that they know what they are doing, indeed.
My personal taste is that it's nicer to explicitly break something rather than implicitly, but I also understand your position.

For reference: Mikolai started working on such an "undo RIOT changes" in #21330 by reflashing the Adafruit Bootloader, but that is riddled by oddities in the adafruit-nrfutil Adafruit nRF52 Bootloader...

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, "explicit" would be better, but for now I think we should prioritize "consistent".

(On the long run I'd like to have something like BOOTLOADER along with BOARD, where the former has a default depending on the latter; not sure how to do that switch in a way that it's apparent to all users what is happening).

@crasbe
Copy link
Contributor

crasbe commented May 21, 2025

There still seems to be an issue with Release 0.2.0, it did not compile successfully on my Linux Mint machine. I wasn't sure where to post this, but considering you're basically the only recent contributor to that project...

chris@ThinkPias:~/RIOTstuff/riot-nrfdongle/RIOT$ sudo cargo install nrfdfu
[sudo] Passwort für chris:
    Updating crates.io index
  Downloaded nrfdfu v0.2.0
  Downloaded 1 crate (98.7 KB) in 0.89s
  Installing nrfdfu v0.2.0
    Updating crates.io index
  Downloaded cfg-if v1.0.0
  Downloaded bitflags v2.9.1
  Downloaded env_filter v0.1.3
  Downloaded clap_lex v0.7.4
  Downloaded digest v0.10.7
  Downloaded anstyle-query v1.1.2
  Downloaded byteorder v1.5.0
  Downloaded crypto-common v0.1.6
  Downloaded cpufeatures v0.2.17
  Downloaded anstyle-parse v0.2.6
  Downloaded utf8parse v0.2.2
  Downloaded version_check v0.9.5
  Downloaded block-buffer v0.10.4
  Downloaded unescaper v0.1.6
  Downloaded is_terminal_polyfill v1.70.1
  Downloaded bitflags v1.3.2
  Downloaded scopeguard v1.2.0
  Downloaded colorchoice v1.0.3
  Downloaded anstyle v1.0.10
  Downloaded thiserror-impl v2.0.12
  Downloaded leb128 v0.2.5
  Downloaded generic-array v0.14.7
  Downloaded quote v1.0.40
  Downloaded anstream v0.6.18
  Downloaded env_logger v0.11.8
  Downloaded thiserror v2.0.12
  Downloaded heck v0.5.0
  Downloaded clap_derive v4.5.32
  Downloaded sha2 v0.10.9
  Downloaded log v0.4.27
  Downloaded proc-macro2 v1.0.95
  Downloaded unicode-ident v1.0.18
  Downloaded crc32fast v1.4.2
  Downloaded clap v4.5.38
  Downloaded serde v1.0.219
  Downloaded typenum v1.18.0
  Downloaded serialport v4.7.2
  Downloaded memchr v2.7.4
  Downloaded clap_builder v4.5.38
  Downloaded aho-corasick v1.1.3
  Downloaded regex v1.11.1
  Downloaded syn v2.0.101
  Downloaded nix v0.26.4
  Downloaded object v0.36.7
  Downloaded regex-syntax v0.8.5
  Downloaded jiff v0.2.14
  Downloaded regex-automata v0.4.9
  Downloaded libc v0.2.172
  Downloaded 48 crates (5.1 MB) in 0.52s
   Compiling proc-macro2 v1.0.95
   Compiling unicode-ident v1.0.18
   Compiling version_check v0.9.5
   Compiling typenum v1.18.0
   Compiling memchr v2.7.4
   Compiling anstyle v1.0.10
   Compiling libc v0.2.172
   Compiling thiserror v2.0.12
   Compiling cfg-if v1.0.0
   Compiling regex-syntax v0.8.5
   Compiling utf8parse v0.2.2
   Compiling clap_lex v0.7.4
   Compiling colorchoice v1.0.3
   Compiling is_terminal_polyfill v1.70.1
   Compiling heck v0.5.0
   Compiling object v0.36.7
   Compiling anstyle-query v1.1.2
   Compiling bitflags v1.3.2
   Compiling anstyle-parse v0.2.6
   Compiling log v0.4.27
   Compiling scopeguard v1.2.0
   Compiling jiff v0.2.14
   Compiling cpufeatures v0.2.17
   Compiling bitflags v2.9.1
   Compiling crc32fast v1.4.2
   Compiling clap_builder v4.5.38
   Compiling anstream v0.6.18
   Compiling leb128 v0.2.5
   Compiling generic-array v0.14.7
   Compiling byteorder v1.5.0
   Compiling aho-corasick v1.1.3
   Compiling quote v1.0.40
   Compiling syn v2.0.101
   Compiling regex-automata v0.4.9
   Compiling block-buffer v0.10.4
   Compiling crypto-common v0.1.6
   Compiling digest v0.10.7
   Compiling nix v0.26.4
   Compiling sha2 v0.10.9
   Compiling regex v1.11.1
   Compiling thiserror-impl v2.0.12
   Compiling clap_derive v4.5.32
   Compiling env_filter v0.1.3
   Compiling env_logger v0.11.8
   Compiling unescaper v0.1.6
   Compiling serialport v4.7.2
   Compiling clap v4.5.38
   Compiling nrfdfu v0.2.0
error[E0658]: use of unstable library feature 'iter_repeat_n'
   --> /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nrfdfu-0.2.0/src/elf.rs:138:22
    |
138 |         image.extend(std::iter::repeat_n(0, gap as usize));
    |                      ^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #104434 <https://github.com/rust-lang/rust/issues/104434> for more information

error[E0599]: no method named `is_none_or` found for enum `Option` in the current scope
   --> /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nrfdfu-0.2.0/src/main.rs:120:26
    |
117 |                       && args
    |  ________________________-
118 | |                         .serial
119 | |                         .as_ref()
120 | |                         .is_none_or(|s| Some(s) == usb.serial_number....
    | |                         -^^^^^^^^^^ help: there is a method with a similar name: `is_none`
    | |_________________________|
    | 

Some errors have detailed explanations: E0599, E0658.
For more information about an error, try `rustc --explain E0599`.
error: could not compile `nrfdfu` (bin "nrfdfu") due to 2 previous errors
error: failed to compile `nrfdfu v0.2.0`, intermediate artifacts can be found at `/tmp/cargo-installqPmfBd`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

@chrysn
Copy link
Member Author

chrysn commented May 21, 2025 via email

@crasbe
Copy link
Contributor

crasbe commented May 21, 2025

Just to clarify beforehand: I'm just trying to figure out how to make the installation process as seamless as possible for the user. I'm not expecting support from you nor do I want to derail this PR. We can also move this discussion to the nrfdfu repo.


Unfortunately rustup does not seem to want to update the Rust installation that was installed with apt.

The best approach would probably to uninstall rust with apt and install a more recent version with rustup and perhaps not even installing rustup with snap, as that does not have the self updates enabled...

cbuec@W11nMate:~$ rustup update
Command 'rustup' not found, but can be installed with:
sudo snap install rustup

cbuec@W11nMate:~$ sudo snap install rustup
error: This revision of snap "rustup" was published using classic confinement and thus may perform
       arbitrary system changes outside of the security sandbox that snaps are usually confined to,
       which may put your system at risk.

       If you understand and want to proceed repeat the command including --classic.

cbuec@W11nMate:~$ sudo snap install rustup --classic
2025-05-21T19:38:58+02:00 INFO Waiting for automatic snapd restart...
rustup 1.27.1 from Canonical✓ installed

cbuec@W11nMate:~$ rustup update
info: no updatable toolchains installed
info: cleaning up downloads & tmp directories
info: self-update is disabled for this build of rustup
info: any updates to rustup will need to be fetched with your system package manager

cbuec@W11nMate:~$ sudo rustup update
info: no updatable toolchains installed
info: cleaning up downloads & tmp directories
info: self-update is disabled for this build of rustup
info: any updates to rustup will need to be fetched with your system package manager

cbuec@W11nMate:~$ apt show rustc
Package: rustc
Version: 1.75.0+dfsg0ubuntu1~bpo0-0ubuntu0.22.04
Priority: extra
Section: devel
Origin: Ubuntu
Maintainer: Ubuntu Developers <[email protected]>
Original-Maintainer: Debian Rust Maintainers <[email protected]>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
...

Apparently newer versions of Ubuntu also ship with Rust 1.75.0: https://launchpad.net/ubuntu/+source/rustc
If I read this list correctly, even the very latest Ubuntu releases ship with Rust 1.75.0: https://launchpad.net/rustc/+packages

From what I've read, it is possible to specify a minimum required Rust version in the Cargo.toml file, that would at least give a more meaningful error message, although I don't really know a way forward from there tbh.
"Uninstall cargo and rustc from your system, install rustup, install rust, install cargo, install nrfdfu and then you can program the Dongle." is not really the hassle-free installation you originally envisioned 😞

@chrysn
Copy link
Member Author

chrysn commented May 21, 2025

That's good input and resulted in knurling-rs/nrfdfu-rs#28.

For the larger issue of having a suitable Rust, yes we should get better catching that in the build system, but this is no new requirement from here: We've had Rust code as part of non-demo examples for a while (microbit-v2 running the saul example had the lsm303agr driver since 2022), and while the cargo/rustc shipped by distros has sometimes been recent enough to build native, those rustc builds don't ship libcore for thumb targets, so effectively users need a rustup Rust.

For some users this is mitigated by BUILD_IN_DOCKER -- and for those we can (and should) enhance usability without requiring rustup (given they have a perfectly sufficient rust version in their build but not their flashing environment). Lowering version requirements would be a step, but the better step is probably integrating with cargo-binstall / cargo-quickinstall (which doesn't even need local cargo when done right) -- and that's something I could do in the follow-up to #21466 (comment).

@chrysn chrysn mentioned this pull request May 22, 2025
@crasbe
Copy link
Contributor

crasbe commented May 24, 2025

So what is the game plan with this? Do you want to create a fixup-version 0.2.1 for nrfdfu-rs first?
Perhaps add some info to the documentation that Rust shouldn't be installed through the package manager for this to work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: boards Area: Board ports Area: doc Area: Documentation CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants