-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
usb: device_next: implement USB DFU class for the new device support #79794
base: main
Are you sure you want to change the base?
usb: device_next: implement USB DFU class for the new device support #79794
Conversation
@@ -0,0 +1,153 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@de-nordic @nordicjm could you review this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing on an nrf52840dk:
- This allows downloading of slot data, but does not enable MCUboot, so this doesn't make sense (sysbuild.conf with
SB_CONFIG_BOOTLOADER_MCUBOOT=y
) - It seems to time out on the try, finishes, then locks up:
sudo dfu-util -d "2fe3:0005" -a 1 -U test.bin
dfu-util 0.11
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Opening DFU capable USB device...
Device ID 2fe3:0005
Device DFU version 0110
Claiming USB DFU (Run-Time) Interface...
Setting Alternate Interface zero...
Determining device status...
DFU state(0) = appIDLE, status(0) = No error condition is present
Device really in Run-Time Mode, send DFU detach request...
Device will detach and reattach...
Opening DFU USB Device...
Claiming USB DFU Interface...
Setting Alternate Interface #1 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 0110
Device returned transfer size 512
Copying data from DFU device to PC
Upload [======================== ] 99% 351744 bytesdfu-util:
Error during upload (LIBUSB_ERROR_TIMEOUT)
Upload [======================== ] 99% 479232 bytes
Received a total of 479232 bytes
At this point, it won't work again:
sudo dfu-util -d "2fe3:0005" -a 1 -U test.bin
dfu-util 0.11
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
dfu-util: Broken LANGID string descriptor
Opening DFU capable USB device...
Device ID 2fe3:ffff
Device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Interface #1 ...
Determining device status...
dfu-util: error get_status: LIBUSB_ERROR_TIMEOUT
And after this the device name part fails:
sudo dfu-util -l
dfu-util 0.11
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
dfu-util: Failed to retrieve language identifiers
dfu-util: Failed to retrieve language identifiers
Found DFU: [2fe3:ffff] ver=0307, devnum=22, cfg=1, intf=0, path="3-3", alt=1, name="UNKNOWN", serial="UNKNOWN"
Found DFU: [2fe3:ffff] ver=0307, devnum=22, cfg=1, intf=0, path="3-3", alt=0, name="UNKNOWN", serial="UNKNOWN"
I only have one USB cable so it's possible that there is an error on the UART and I can't see it
Same story with the RAM disk:
sudo dfu-util -d "2fe3:0005" -a 0 -U test.bin
dfu-util 0.11
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Opening DFU capable USB device...
Device ID 2fe3:ffff
Device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 0110
Device returned transfer size 512
Copying data from DFU device to PC
Upload [======================== ] 99% 512 bytesdfu-util:
Error during upload (LIBUSB_ERROR_TIMEOUT)
Upload [======================== ] 99% 16384 bytes
Received a total of 16384 bytes
sudo dfu-util -d "2fe3:0005" -a 0 -U test.bin
dfu-util 0.11
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
dfu-util: Broken LANGID string descriptor
Opening DFU capable USB device...
Device ID 2fe3:ffff
Device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
dfu-util: error get_status: LIBUSB_ERROR_TIMEOUT
Offsets make no sense, the file you get from the device, supposedly for slot0, has lots of 0xff's then at 0x1736c has "mutex_free called", if I read the code from the device using nrfjprog and search, I find one result at 0x2236c, which is a 0xb000 difference, this doesn't make sense. Can see here from the zephyr.dts file that the application starts at 0xc000:
|
* It is very unlikely that anyone would need more than one instance of the DFU | ||
* class. Therefore, we make an exception here and do not support multiple | ||
* instances, which allows us to have a much simpler implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure if this will bite us later or not. One example that comes to mind is device with two independent USB device controllers running separate instances of USB stack. The example may be a bit far stretched, but there are SoCs on the market with hardware capable for running two separate USB device stack instances at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have thought about that. DFU is not a normal operating mode, I think it is quite unlikely that there will be a need to have two USB devices on the same SoC with DFU capabilities.
|
||
config USBD_DFU_NUMOF_IMAGES | ||
int "Number of possible DFU images" | ||
range 1 255 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment in DFU class instance says the range is 0..255 with maximum being 256 images. Should this range be changed to range 1 256
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfischer-no you put a thumbs up but the code is still unchanged. Should it be range 1 256
or range 1 255
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, should be fixed now.
subsys/usb/device_next/usbd_class.c
Outdated
static bool is_disallowed(const struct usbd_class_node *const c_nd) | ||
{ | ||
static const char *const list[] = { | ||
"dfu_dfu", | ||
}; | ||
|
||
for (int i = 0; i < ARRAY_SIZE(list); i++) { | ||
if (strcmp(c_nd->c_data->name, list[i]) == 0) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just doesn't seem right. This is essentially a blocklist for usbd_register_all_classes()
which is not even documented.
Yes, MCUboot is just some bootloader library, never really integrated into the Zephyr project. You have built the example with
Yes, there is a bug in USBD controller driver. |
This is completely false, it is integrated with zephyr, hence why doing |
240dfd2
to
f2bdaf2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issues:
- Needs a
sysbuild.conf
file withSB_CONFIG_BOOTLOADER_MCUBOOT=y
in - Does not work if USB cable is attached when application starts, it needs to be removed then re-inserted
Why is it needed and where do you get these requirements from?
What application? Please give me some more information about what you are trying to do. |
You have a sample here that writes slot1 partition, so what use is building a sample that can't actually be used (i.e. without mcuboot)? You added slot1 to dfu, so doing an upload should work and be testable by users
The sample here? Connect nrf5340dk up using both ports, build and flash, then see after boot that there is no USB device detected on the host PC, then unplug only the nRF USB port and plug it back in, now it appears |
First of all, this is a sample, not an application, and MCUboot is just some bootloader library. There is no need to bind the USB DFU to a specific bootloader library. The user can simply test the upload/download of the slot 1 image or the RAMdisk using dfu-utils. The user can have similar functionality as to the legacy sample by using "CONFIG_BOOTLOADER_MCUBOOT=y". |
96febfc
to
9c208c7
Compare
This is a bug in the usbreg driver in nrfx that will be solved later and only affects nRF5340, nothing to do with the USB DFU class. Please use an nRF52840 instead. |
Yes, but MCUboot is officially supported and integrated with Zephyr.
and adding a Users are still free to do:
and nothing prevents the user from doing so, even if you include a
What's the problem in making a better out-of-the-box experience for users testing this sample by supporting automatic inclusion of MCUboot when building with sysbuild ? A lot of good and valuable review comments cannot be traced back to a specific requirement, but they are still accepted by PR authors to provide an even better user experience. Just like a lot of PRs in Zephyr itself are opened without a specific requirement for the feature proposed. |
No, it is the sample for USB DFU class implementation. This sample also supports flash backend and provides information on how to build and test it with MCUboot. Again, as you continue to make false assumptions here, support for MCUboot is outside the Zephyr project, there is no porting layer in Zephyr for MCUboot. There is no rule to support only MCUboot or to use only MCUboot for firmware updates.
To load firmware into RAM, of course. Like we have MSC sample using RAMdisk per default. There are even people who run code in RAM. Or to provide an example of how to implement your own backend to whatever memory, bootloader, subsystem, as other samples provide an example. Users have asked for this. Finally, this allows users to try out implementation and host tools without using bootloader and flash, avoiding all the nightmares with boards flash configurations and exclusions in the legacy sample.
No, I did not say that. That is your assumption. This sample provides a simple example to try the USB DFU implementation and a more advanced configuration to try it with the flash backend. The documentation provides examples for these use cases, even how to build with sysbuild. I have read nothing useful from you here, absolutely nothing, you are circling around with your false assumptions. So please either read the code and documentation and provide some useful feedback or just dismiss your review and let this move forward. |
Ping @kartben on this, this is now what, the 3rd time you've made comments that are flat out wrong, the first time was in the dev working group where you said similar things and I'm getting tired of hearing these wrong comments. MCUboot is integrated into zephyr, it is the default and only supported cross device bootloader in tree (not to say it's the only bootloader zephyr can use) and therefore is the default |
Porting layer for MCUboot is https://github.com/mcu-tools/mcuboot/tree/main/boot/zephyr, what is not Zephyr project repository, unlike other modules, e.g. LVGL, there is no zephyr/modules/mcuboot, what is against "Zephyr modules should not contain code that is written exclusively for Zephyr. Instead, such code should be contributed to the main zephyr tree.". So it is other way around, Zephyr is integrated in MCUboot. You know that, your are one of the contributor. So, again do you @nordicjm have anything to contribute to USB device support? |
8d32019
to
0adc27b
Compare
agree with @jfischer-no, USB-DFU class feature deserves its own sample and is not related with any existing update features available through mcuboot or anything else. |
This is the equivalent of trying to classify a fish by looking at 1 pixel and nothing more, MCUboot is a zephyr application with it's own infrastructure, development/release cycle and development team/organisation supporting more than just zephyr, there's plenty of "porting layer" files inside of zephyr: https://github.com/zephyrproject-rtos/zephyr/tree/main/subsys/dfu https://github.com/zephyrproject-rtos/zephyr/tree/main/subsys/mgmt/mcumgr/grp/img_mgmt https://github.com/zephyrproject-rtos/zephyr/blob/main/cmake/mcuboot.cmake so no you are wrong
This is not a sample really, it's useless. In the default configuration you an upload a new firmware image that you can never use, you can also upload to a ramdisk image which, again, you can never use, so if there is to be such a project it should go in tests. This is on par with having a low power sample where when you open the main.c file it's just a comment "write the code yourself" |
I can do that, I am a fish expert, I have it in my last name, even in the avatar is one.
Nope, that are dependencies (although DFU subsystem can be used with different bootloader library). This does not make it better, but it does make it more obvious that the MCUboot module violates Zephyr modules should not contain code that is written exclusively for Zephyr. Instead, such code should be contributed to the main zephyr tree..
The sample allows easy access for the user, it provides easy configuration to build and flash sample quickly without any dependencies but only small portion or RAM and get them familiar with USB DFU implementation and host tools. This is not what tests should do. There is also another option to build the sample with the flash backend enabled (flash backend uses the DFU subsystem which does not really have MCUboot dependencies) and if the user wants they can use it with MCUboot. I still do not see any valuable contribution from you in this review. Do you @nordicjm have anything to contribute to USB device support? |
Obviously that only applies to libraries, not applications. MCUboot is a special case because it is a Zephyr application, not a 3rd-party library, and it is quite obvious that you cannot write a Zephyr applications without using Zephyr code and APIs. I will send a doc patch to fix this. |
You mean MCUboot is an application? |
You must have glossed over first half of this post: #79794 (comment) |
It is both, of course.
That is your opinion, I disagree with that. In the particular case of a bootloader, and MCUboot in particular, it makes all the sense in the world for Zephyr to pull it as a module, but for the app to be maintained in the MCUboot project. We could of course ask them to move the app to the main Zephyr tree, but then they would lose control over it, which may not be what they (or us) want. |
whether it is a sample, a test or something else is beside the point, we have this issue in majority of what we call samples. USB DFU class deserves its own sample without pulling the mcuboot into the discussion, how useful it is and if it needs to be changed to become useful is up for discussion. |
@carlescufi How is But that is tangential, there is clearly no rule to use only the MCUboot "application" library, or to provide firmware update examples using the MCUboot "application" library. You can just ignore what I write about how badly MCUboot is coupled with the Zephyr project. I made my point as maintainer for this PR here, there was literally nothing contributed to the review from @nordicjm. |
I did not say that this particular item was your opinion. I said that there should be an exception in that text for bootloaders. Then I said that it was your opinion that modules should not be an application. Those are two different things. |
"Zephyr relies on the source code of several externally maintained projects in order to avoid reinventing the wheel and to reuse as much well-established, mature code as possible when it makes sense." That sound to me like a library description, but yeah, maybe that is just my interpretation, I would never think that including an application in the default manifest of the Zephyr project would be a good idea. |
In the usbd_register_all_classes(), we may need to skip some instances as they may have very specific function like USB DFU "DFU mode" which should not be available by default. Signed-off-by: Johann Fischer <[email protected]>
This new implementation is written from scratch and is not tied to the image manager and MCUboot. It allows the user to define their own backend and use a simple macro to instantiate an image. On the USB side this is represented by an interface. The number of possible images is configurable using the Kconfig option, and is a fairly inexpensive approach since it only changes the size of the pointer array. The number of images is only limited by the number of possible interfaces in a configuration. The class implementation does not support multiple instances, as there is no real use for it. However, it does provide two class instances, one for runtime mode and one for DFU mode. The switch from runtime to DFU mode can only be performed by the user application, i.e. the application receives a notification when the host wants to switch to DFU mode, and then the application can disable the runtime configuration and enable the DFU configuration. This implementation does not support switching to the DFU mode by bus reset issued by the host. Signed-off-by: Johann Fischer <[email protected]>
Add a simpler flash backend, similar to what we have in the legacy USB DFU implementation. Support slot-0 and slot-1 flash partitions, but allow them to be enabled/disabled via Kconfig options. Signed-off-by: Johann Fischer <[email protected]>
The sample defines an image that uses RAMdisk and also provides an option to enable USB DFU flash backend for the "slot-1" flash partition. Assuming the user runs this sample from the slot-0 partition, uploading to flash should work fine for evaluation purposes. If the sample is built with CONFIG_BOOTLOADER_MCUBOOT=y, the sample will mark the image in slot 1 as pending after an image download. Signed-off-by: Johann Fischer <[email protected]>
0adc27b
to
c68a721
Compare
Not really? MCUboot is:
|
I don't really follow this, MCUboot has been in zephyr longer than I've used it, and I started using it with 1.13? in 2017-ish, llext wasn't added until zephyr... 3.5, and I can't see how this example is used with llext. Zephyr moves on, back in 1.x there was no sysbuild, if you wanted MCUboot in a project, you needed to go and configure and build MCUboot, then configure and build your application, flash them both and hope the configuration was correct. Now you just build an application with sysbuild and the Kconfig for it and you automatically get your application and MCUboot built, and it's a fully compatible configuration. |
@carlescufi I have trouble processing some statements. I need some help to clarify that. Does the following text describe a library or not? If Zephyr would have to write an bootloader code similar to MCUboot's it would be an library or would we call it application? Is there a rule, that also applies to external "applications" if they are modules, that states that to be classified as a candidate for being included in the default list of modules "Zephyr modules should not contain code that is written exclusively for Zephyr. Instead, such code should be contributed to the main zephyr tree.", or not? Two questions to Arch WG: Does the Zephyr project code only have to use the MCUboot application and not provide any other interfaces to implement firmware updates? Does "firmware update" only mean an update mechanism using Flash APIs, and does the firmware always have to reside in Flash? And: "Samples should be limited in scope and should focus only on demonstrating non-trivial or essential aspects of the subsystem(s) or module(s) being highlighted." This sample is for USB device support, the scope is to show how to use USB DFU implementation. USB DFU device configuration is non-trivial. Essential aspect is the implementation of a backend or the use of flash backend. Does this sample meet the sample criteria documented here? If not, why not? |
Unfortunately, this sample also needs to cover the upload/download to flash use case (using DFU subsys) to provide similar functionality as the legacy sample. What it does and provide documentation on how to do it, and even how to use it with sysbuild and MCUboot. The user can even see how to use the built-in flash backend and how to implement a custom one. So am actually very confused as to how this can be useless. Finally, this does not force us to keep the long platform exclude list, because we cannot really filter platforms with flash problems or without partitions, because the flash maintainer does not care to provide testing features that would allow the twister to better filter.
I looked at LLEXT, but it would make it more complicated, especially for the new users. I may be wrong, but not all architectures work well with LLEXT. But this is a nice use case (and also applies to #62286) and something for the example applications. |
fun. I did not say llext was used at any point, saying that this could be used. Zephyr was not launched with mcuboot support, mcuboot came at some point later. Zephyr was lauched primarily to support an arduino product among other things (arduino 101 based on intel curie) and the mode of updating the sketch and updates in general was usb dfu. Just saying, USB DFU is a thing, it can exist on its own and without sysbuild/mcuboot and all of that. |
hi, i was not saying it was useless, I honestly just skimmed through the code very fast, my point is, that is a different discussion. |
|
@jfischer-no is right here, not sure what usb dfu has to do with mcuboot... Zephyr in the past had samples showing how to use usb dfu without any mcuboot involvement. DFU is a protocol, sample should show how to implement some hooks the protocol sets up I'd think? Loading an image directly to ram and jumping to it is actually pretty nice, sometimes boot rom's support this sort of boot from usb/serial type functionality without any bootloader to speak of. LLEXT would basically let you load an image into memory without explicitly linking it to specific memory locations which could be interesting but its not required to say... have a boot from usb type functionality here with dfu. |
Add USB DFU class implementation for the USB device support.
Add flash backend and sample.