usb-device
usb-device copied to clipboard
Compile-time descriptor generation
Allocating endpoints, validating the configuration, and generating the descriptors is something that could be done at compile time. The result would be a bit of generated code that configures endpoints, and a binary blob with the descriptor that can be sent to the host as-is.
This would reduce runtime errors as well as make the footprint of the library smaller because the descriptor blob should be much smaller than the code used to generate it at the moment.
This loses the ability to easily make dynamic USB devices at runtime, but it's very unlikely people would ever need to do that. It would still be possible by writing your own descriptor generation code.
What comes to implementation, proc-macros probably can't do it because the generation code will need to look at type information and call into code in potentially three or more crates (the user's binary, the peripheral driver crate and class crates) to generate everything. const fn
s will likely be a viable option in the future, but they seem too limited at the moment. Currently the only candidate that seems viable for compile time descriptor generation is using a build.rs
. This means though that the end-user will have to add a small build.rs
to their projects, which is pretty annoying.
I haven't used proc-macros so fare so this is goes work.
How about invoking a proc-macro at multiple points that collets the information into a single file.
Maybe directly rust code or some abstract representation that is compiled later with in build.rs
in some crate.
The problem would be that its probably not possible to control the order in which the entry would be added.
I am also unsure how clean it is to generate files like this.
I think the build order is so that any build.rs code is run before the proc-macros invoked in any user code have had a chance to run. It's worth investigating if it would be possible though, because it would be very nice to avoid having a build.rs in every project.
ya you are right build.rs executes befor compiling the crate and so befor the proc-macro.
The CONTROL_BUF_LEN
could/should then also be set to optimal size, current setting at 128 bytes is too small for big descriptors.
wrt the buffer size compile time generated descriptors can be read directly from flash and don't need to use the buffer at all - it could even be smaller. It needs to be configurable though.
Before the compile time descriptors happen, maybe https://github.com/jamesmunns/mcf-config-demo could be a nice approach to configure CONTROL_BUF_LEN
(and possibly other things). What do you think?
@nickray Does that trick absolutely require an extra crate just for changing the settings or does it work without? If so I'd be inclined to use something like this instead: https://docs.rs/generic-array/0.13.0/generic_array/
Yes, that's the whole idea of the trick: A "config file" crate that has sane defaults, but can be patched out via Cargo by the user of usb-device
. If you use this I'd tend to go for "large"/"should always work" sizes, letting the user pick an appropriately minimal size.
One alternative like you say is generic-array
, downside IMO is type ado about nothing :)
We had a discussion on IRC last night, third option might be to use build.rs
, to quote @jamesmunns:
I think a library build.rs should be able to see the project dir, and could look for a config-embedded-hal.toml file
I guess you could also just have a feature bigger-control-buffer
that uses 256 or some such number (happens to be enough for my use case).
Aaahh, it uses a [patch] section, I didn't even realize at first... right, right.
Maybe in the future we can have compile time constants with values as opposed to just features.