# device-register
[](https://crates.io/crates/device-register) [](https://docs.rs/device-register)
A `no_std`, zero cost toolkit to describe the registers of a device to ease driver development.
* `no_std` support
* Zero cost, no use of dyn
* No dsl, just a derive macro and impl a trait.
* Error passthrough
### Usage
Simply derive using `XXRegister`, where XX is the premission.
The following permissions are supported
* [`RORegister`](crate::RORegister), read only permission
* [`WORegister`](crate::WORegister), write only permission
* [`EORegister`](crate::EORegister), edit only permission, when a register need to be read-modify-write
* [`RERegister`](crate::RERegister), Read and edit permission
* [`RWRegister`](crate::RWRegister), Read, write and edit permission.
To define a register, simply derive using the desired permission.
Then use the `register` attribute to define it's address, type for the address and the error.
```rust
#[derive(RWRegister)]
#[register( addr = "42", ty = "u8")]
pub struct Register0(pub u16);
```
Then, your driver only need to implement the [RegisterInterface](crate::RegisterInterface) to have access to the read/write/edit traits.
#### Complete example
Here is a complete example.
See the `tests` folder for more, or checkout the [tmp117](https://github.com/xgroleau/tmp117-rs) driver for actual usage.
```rust
use std::collections::HashMap;
use device_register::*;
// The type of the address used by the driver
struct Address(pub u8);
// We define the register with Read/Write permission
// Then we pass the address type, value and error type of the driveer
#[derive(Debug, Copy, PartialEq, Eq, Clone, RWRegister)]
#[register( addr = "Address(1)", ty = "Address")]
struct Register0(pub u16);
// Mock of the device driver
struct DeviceDriver {
// Simulate reading from the device
pub registers: HashMap<u8, u16>,
}
// Implement a method directly, by passing the trait for specific usecases like async
impl DeviceDriver {
pub async fn read_async<R>(&self) -> R
where
R: ReadableRegister<Address = Address> + From<u16>,
{
async {
let bytes = self.registers.get(&R::ADDRESS.0).unwrap();
bytes.clone().into()
}.await
}
}
// We implement the required interface
impl<R> RegisterInterface<R, Address> for DeviceDriver
where
R: Register<Address = Address> + Clone + From<u16>,
u16: From<R>,
{
// The type of the error, lets have none for now,
type Error = ();
fn read_register(&mut self) -> Result<R, Self::Error> {
let bytes = self.registers.get(&R::ADDRESS.0).unwrap();
Ok(bytes.clone().into())
}
fn write_register(&mut self, register: &R) -> Result<(), Self::Error> {
self.registers.insert(R::ADDRESS.0, register.clone().into());
Ok(())
}
}
let mut device = DeviceDriver{
registers: HashMap::new(),
};
// We can the Read/Write/Edit the registers that uses the Address and DeviceError types.
let write = Register0(42);
device.write(write).unwrap();
let read: Register0 = device.read().unwrap();
assert_eq!(read, write);
r
}).unwrap();
let read: Register0 = device.read().unwrap();
assert_eq!(read, Register0(43));
// Custom implementation, async is an example of usecase for custom implements
tokio_test::block_on( async {
let read_async: Register0 = device.read_async().await;
assert_eq!(read, Register0(43));
} );
```
### License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
### Contribution
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.