A toolkit to write better device drivers, faster.
This crate is a set of traits to represent devices, registers and commands. You can make use of macros to implement the registers and commands in a convenient way.
With quite some ease you can give users a blocking and an async interface to the device.
Currently you've got these options:
Feedback and feature requests are appreciated! Just open an issue on github. I want to add more features to this crate, but only once I (or maybe you) need them.
I realise the documentation is a bit lacking, but the examples should be pretty straightforward. For a real driver example using this crate you can also look at: https://github.com/diondokter/s2lp
Still wanted:
Note: Until https://github.com/illicitonion/num_enum/pull/77 gets merged, you'll need to import the num_enum in the crate where the device-driver macro is used. This needs to be added to the Cargo.toml
. Trying to import the re-export from device-driver is not enough.
This crate consists of three parts:
device-driver
: The main crate that re-exports everything needed. It defines a set of traits
the represent a device and a register. The device traits are to be implemented by the
driver crate to let the system know how registers are read and written.
This all is done with the register trait which contains all information needed about the register.
One could implement the registers and their fields manually, but this crate provides very nice
functionality to generate all that.device-driver-generation
: This is as it were the backend. It has definitions of a sort of intermediate
representation of a device and its registers and fields. From there it can generate rust
code that implements the aforementioned device-driver traits.
It also provides custom serde
deserialization routines for various types to make them
conveniently expressable.device-driver-macros
: Contains all of the proc macros. One macro takes a path to a definitions file.
It then uses serde to deserialize it into the 'generation' representation. The other macro defines a
custom Rust syntax and turns that into the 'generation' representation. Both then generate the
implementation of the registers and their fields.Anything that can reasonably break user code will warrant a breaking semver bump. This includes the macro format and file register definition formats.
The generation
and macros
crates are considered internal and so might not be as strict in their semver bumps. This is mostly to keep them somewhat in line with the version of the main crate.
If you depend on these crates directly, please let me know! If I know those have direct users, I will be stricter with the versions.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
From<primitive>
instead of TryFrom<primitive>
.
But reading the register field is then not a result.async
feature flag to activate it.
When you do, you will have access to the ll::register_async
module that will generate async code for you.Debug
impls to all register R
that prints the raw value in hex.
There's now also the option (#[generate(Debug)]
) to get an even better Debug
impl that also prints out all the fields,
but does require all fields to impl Debug
themselves.
See (#10) to see how it works.