1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
//! Device electronic signature
//!
//! (stored in flash memory)
use core::fmt;
use core::str;
const UID_PTR: u32 = 0x1FFF_F7AC;
use core::convert::TryInto;
impl Uid {
fn ptr() -> *const Self {
UID_PTR as *const _
}
/// Returns a wrapped reference to the value in flash memory
#[must_use]
pub fn get() -> &'static Self {
// SAFETY: The Uid pointer is definitly correct and as it is only ever shared immutable
// mutliple references to it are fine.
unsafe { &*Self::ptr() }
}
}
/// Uniqure Device ID register
#[repr(C, packed)]
pub struct Uid {
x: u16,
y: u16,
waf: u8,
lot: [u8; 7],
}
#[cfg(feature = "defmt")]
impl defmt::Format for Uid {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"Peripheral {{ x: {:x}, y: {:x}, waf: {}, lum: {}}}",
{ self.x },
{ self.y },
{ self.waf },
{ self.lot_number() },
);
}
}
impl fmt::Debug for Uid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Uid")
.field("x", &self.x())
.field("y", &self.y())
.field("waf", &self.waf)
.field("lot", &self.lot_number())
.finish()
}
}
fn bcd_to_num(bcd_num: u16) -> u16 {
bcd_num
.to_ne_bytes()
.iter()
.enumerate()
.map(|(i, byte)| (i * 2, (*byte & 0xF0) >> 4, *byte & 0x0F))
.map(|(i, high_nibble, low_nibble)| {
let i: u32 = i.try_into().unwrap_or_default(); // This should never overflow
u16::from(high_nibble) * 10u16.pow(i + 1) + u16::from(low_nibble) * 10u16.pow(i)
})
.sum()
}
impl Uid {
/// X coordinate on wafer in BCD format
#[must_use]
pub fn x_bcd(&self) -> u16 {
self.x
}
/// X coordinate on wafer
#[must_use]
pub fn x(&self) -> u16 {
bcd_to_num(self.x)
}
/// Y coordinate on wafer in BCD format
#[must_use]
pub fn y_bcd(&self) -> u16 {
self.y
}
/// Y coordinate on wafer
#[must_use]
pub fn y(&self) -> u16 {
bcd_to_num(self.y)
}
/// Wafer number
#[must_use]
pub fn wafer_number(&self) -> u8 {
self.waf
}
/// Lot number
#[must_use]
pub fn lot_number(&self) -> &str {
// Lets ignore the last byte, because it is a '\0' character.
// TODO: change to core::ffi::CStr
// SAFETY: It is assumed that the lot number only contains valid ASCII characters
unsafe { str::from_utf8_unchecked(&self.lot[..6]) }
}
}
/// Size of integrated flash
#[derive(Debug)]
#[repr(C)]
pub struct FlashSize(u16);
const FLASH_PTR: u32 = 0x1FFF_F7CC;
impl FlashSize {
fn ptr() -> *const Self {
FLASH_PTR as *const _
}
/// Returns a wrapped reference to the value in flash memory
#[must_use]
pub fn get() -> &'static Self {
// SAFETY: The FlashSize pointer is definitly correct and as it is only ever shared immutable
// mutliple references to it are fine.
unsafe { &*Self::ptr() }
}
}
impl FlashSize {
/// Read flash size in kilobytes
#[must_use]
pub fn kilo_bytes(&self) -> u16 {
self.0
}
/// Read flash size in bytes
#[must_use]
pub fn bytes(&self) -> usize {
usize::from(self.kilo_bytes()) * 1024
}
}