forked from ariel-os/ariel-os
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(device-id): Add to riot-rs and the archs
- Loading branch information
Showing
16 changed files
with
255 additions
and
7 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
//! Tools and traits for describing device identities. | ||
//! | ||
//! See `riot_rs::identity` for general documentation. | ||
#![deny(missing_docs)] | ||
|
||
/// Trait describing the unique identifier available on a board. | ||
/// | ||
/// See the module level documentation on the characteristics of the identifier. | ||
/// | ||
/// # Evolution | ||
/// | ||
/// In its current state, this type is mainly a wrapper around a binary identifier with a | ||
/// length constant at build time. | ||
/// | ||
/// As it is used more, additional methods can be provided for concrete types of identifiers, such | ||
/// as MAC addresses. By default, those would be generated in some way from what is available in | ||
/// the identifier -- but boards where the identifier already *is* a MAC address (or possibly a | ||
/// range thereof) can provide their official addresses. | ||
/// | ||
/// This trait is `Sealed` in the `riot-rs-embassy-common` crate to ensure that associated types | ||
/// and non-provided methods can be added. Therefore, its re-export in the `riot-rs` crate is a | ||
/// promise that the trait evolves at the (slower) `riot-rs` speed towards users, while it can | ||
/// evolve at the (possibly faster) RIOT-rs internal speed of `riot-rs-embassy-common` for | ||
/// implementers. | ||
pub trait DeviceId: Sized + core::fmt::Debug + defmt::Format + crate::Sealed { | ||
/// Some `[u8; N]` type, returned by [`.bytes()`][Self::bytes]. | ||
/// | ||
/// This may not represent all the identifying information available on the board, but can | ||
/// represent a unique portion thereof. | ||
/// | ||
/// (For example, if a device has two consecutive MAC addresses assigned, the type as a whole | ||
/// may represent both, but the conventional serialized identity of the board may just be one | ||
/// of them). | ||
/// | ||
/// # Evolution | ||
/// | ||
/// In the long run, it will be preferable to add a `const BYTES_LEN: usize;` and enforce the | ||
/// type `[u8; Self::BYTES_LEN]` as the return value of [`.bytes(_)]`][Self::bytes]. This can | ||
/// not be done yet as it depends on the `generic_const_exprs` featureVg | ||
type Bytes: AsRef<[u8]>; | ||
|
||
/// Obtains a unique identifier of the device. | ||
/// | ||
/// For callers, there is the convenience function `riot_rs::identity::device_identity()` | ||
/// available, which just calls this trait method on `riot_rs::arch::identity::DeviceId`. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This produces an error if no device ID is available on this board, or is not implemented. | ||
/// It is encouraged to use [`core::convert::Infallible`] where possible. | ||
fn get() -> Result<Self, impl Error>; | ||
|
||
/// The device identifier in serialized bytes format. | ||
fn bytes(&self) -> Self::Bytes; | ||
} | ||
|
||
/// Error trait for obtaining [`DeviceId`]. | ||
/// | ||
/// This is part of the signature of [`DeviceId::get`], and indicates that no identifier is | ||
/// available. | ||
/// | ||
/// Like [`DeviceId`], it is sealed; the same considerations for stability as listed there apply. | ||
pub trait Error: core::error::Error + defmt::Format + crate::Sealed {} | ||
|
||
impl crate::Sealed for core::convert::Infallible {} | ||
impl Error for core::convert::Infallible {} | ||
|
||
/// An uninhabited type implementing [`DeviceId`] that always errs. | ||
/// | ||
/// This can be used both on architectures that do not have a unique identifier on their boards, | ||
/// and when it has not yet been implemented. | ||
/// | ||
/// Typical types for `E` are [`NotImplemented`] or [`NotAvailable`]. | ||
#[derive(Debug, defmt::Format)] | ||
pub struct NoDeviceId<E: Error + Default>(core::convert::Infallible, core::marker::PhantomData<E>); | ||
|
||
impl<E: Error + Default> crate::Sealed for NoDeviceId<E> {} | ||
|
||
impl<E: Error + Default> DeviceId for NoDeviceId<E> { | ||
// We could also come up with a custom never type that AsRef's into [u8], but that won't fly | ||
// once there is a BYTES_LEN. | ||
type Bytes = [u8; 0]; | ||
|
||
fn get() -> Result<Self, impl Error> { | ||
Err::<_, E>(Default::default()) | ||
} | ||
|
||
fn bytes(&self) -> [u8; 0] { | ||
match self.0 {} | ||
} | ||
} | ||
|
||
/// Error indicating that a [`DeviceId`] may be available on this platform, but is not implemented. | ||
#[derive(Debug, Default, defmt::Format)] | ||
pub struct NotImplemented; | ||
|
||
impl core::fmt::Display for NotImplemented { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
f.write_str("Device ID not implemented on this platform") | ||
} | ||
} | ||
|
||
impl crate::Sealed for NotImplemented {} | ||
impl core::error::Error for NotImplemented {} | ||
impl Error for NotImplemented {} | ||
|
||
/// Error indicating that a [`DeviceId`] is not available on this platform. | ||
#[derive(Debug, Default, defmt::Format)] | ||
pub struct NotAvailable; | ||
|
||
impl core::fmt::Display for NotAvailable { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
f.write_str("Device ID not available on this platform") | ||
} | ||
} | ||
|
||
impl crate::Sealed for NotAvailable {} | ||
impl core::error::Error for NotAvailable {} | ||
impl Error for NotAvailable {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#[derive(Debug, defmt::Format)] | ||
pub struct DeviceId(u64); | ||
|
||
impl riot_rs_embassy_common::Sealed for DeviceId {} | ||
|
||
impl riot_rs_embassy_common::identity::DeviceId for DeviceId { | ||
#[allow( | ||
refining_impl_trait_reachable, | ||
reason = "Making this fallible would be a breaking API change for RIOT-rs." | ||
)] | ||
fn get() -> Result<Self, core::convert::Infallible> { | ||
// Embassy does not wrap the FICR register, and given that all we need from there is a register | ||
// read that is perfectly fine to do through a stolen register, let's do that rather than | ||
// thread the access through several layers. | ||
|
||
// SAFETY: The register is used for read-only operations on constant values. | ||
#[cfg(context = "nrf52840")] | ||
let ficr = unsafe { nrf52840_pac::Peripherals::steal().FICR }; | ||
#[cfg(context = "nrf52832")] | ||
let ficr = unsafe { nrf52832_pac::Peripherals::steal().FICR }; | ||
#[cfg(context = "nrf5340")] | ||
let ficr = &unsafe { nrf5340_app_pac::Peripherals::steal().FICR_S }.info; | ||
|
||
let low = ficr.deviceid[0].read().bits(); | ||
let high = ficr.deviceid[1].read().bits(); | ||
Ok(Self((u64::from(high) << u32::BITS) | u64::from(low))) | ||
} | ||
|
||
type Bytes = [u8; 8]; | ||
|
||
fn bytes(&self) -> Self::Bytes { | ||
self.0.to_le_bytes() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#[derive(Debug, defmt::Format)] | ||
pub struct DeviceId(&'static [u8; 12]); | ||
|
||
impl riot_rs_embassy_common::Sealed for DeviceId {} | ||
|
||
impl riot_rs_embassy_common::identity::DeviceId for DeviceId { | ||
type Bytes = &'static [u8; 12]; | ||
|
||
#[allow( | ||
refining_impl_trait_reachable, | ||
reason = "Making this fallible would be a breaking API change for RIOT-rs." | ||
)] | ||
fn get() -> Result<Self, core::convert::Infallible> { | ||
Ok(Self(embassy_stm32::uid::uid())) | ||
} | ||
|
||
fn bytes(&self) -> Self::Bytes { | ||
self.0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
//! Access to unique identifiers provided by the device. | ||
//! | ||
//! The main way to use this module is [`device_identity()`], which returns an identifier for the | ||
//! concrete piece of hardware that the software is running on. | ||
//! | ||
//! Concrete properties of a device identity are: | ||
//! | ||
//! * Identifiers are reasonably unique: They are either unique by construction (serial number, MAC | ||
//! address) or random identifiers (>= 64 bit). | ||
//! | ||
//! * The scope of the identifier is within a RIOT-rs board. Their scope may be broader, eg. when | ||
//! a identifier is unique per MCU family, or even globally. | ||
//! | ||
//! * Identifiers do not change during regular development with a board, which includes the use of | ||
//! a programmer. Identifiers may change under deliberate conditions, eg. when a device has a | ||
//! one-time programmable identity, or when there is a custom functionality to overwrite the | ||
//! built-in identifier that is not triggered by the device erase that is performed as part of | ||
//! programming the device. | ||
//! | ||
//! Constructing an identifier fails rather than producing a dummy identifier. | ||
//! | ||
//! It is considered a breaking change in a board or this module if a board's identifier changes or | ||
//! becomes an error as result of an update to RIOT-rs. Errors changing to valid identifiers is a | ||
//! compatible change. | ||
#[doc(inline)] | ||
pub use riot_rs_embassy_common::identity::{DeviceId, Error}; | ||
|
||
/// Obtains a unique identifier of the device. | ||
pub fn device_identity() -> Result<impl DeviceId, impl Error> { | ||
riot_rs_embassy::arch::identity::DeviceId::get() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters