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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
//! [](https://crates.io/crates/persistent-buff) [](https://docs.rs/persistent-buff)
//!
//! A buffer that persists between boot.
//! Inspired by [panic-persist](https://github.com/jamesmunns/panic-persist)
//!
//! A region in RAM is reseved for this buffer.
//! Your linker script should make sure the start and end of the buffer are outside of other sections
//!
//! ## Usage
//!
//! ### Linker script
//! You need to create a new reserved section for the buffer and make sure it's
//! outside of other sections to avoid zero initializations.
//!
//! #### Example
//! `memory.x` file before modification:
//!
//! ``` ignore
//! MEMORY
//! {
//! /* NOTE 1 K = 1 KiBi = 1024 bytes */
//! FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
//! RAM : ORIGIN = 0x20000000, LENGTH = 128K
//! }
//! ```
//! `memory.x` file after modification to hold a 1K region:
//! ``` ignore
//! MEMORY
//! {
//! /* NOTE 1 K = 1 KiBi = 1024 bytes */
//! FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
//! RAM : ORIGIN = 0x20000000, LENGTH = 128K - 1K
//! PERSISTENT_BUFF: ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 1K
//! }
//! _persistent_buff_start = ORIGIN(PERSISTENT_BUFF);
//! _persistent_buff_end = ORIGIN(PERSISTENT_BUFF) + LENGTH(PERSISTENT_BUFF);
//! ```
//!
//! ### Program
//!
//! ```ignore
//! #![no_std]
//!
//! #[entry]
//! fn main() -> ! {
//! let mut pbuff = persistent_buff::PersistentBuff::take_managed().unwrap();
//!
//! // Trivial way to initialize is to fill it with 0
//! let buff = pbuff.validate(|b| b.fill(0));
//!
//! buff[0] = (buff[0] % 255) + 1;
//! info!("Value is now {}", buff[0]);
//! }
//! ```
//!
//! ## 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.
#![no_std]
#![no_main]
#![deny(missing_docs)]
use core::sync::atomic::{AtomicBool, Ordering};
const MAGIC_NUMBER: u32 = 0x42069F;
static mut PERSISTENT_BUFF_TAKEN: AtomicBool = AtomicBool::new(false);
/// Strut to request the persistent buff and manage it `safely`.
/// When acquiring the buffer you need to validate it and init it to a known sate
pub struct PersistentBuff {
magic: *mut u32,
buff: &'static mut [u8],
}
impl PersistentBuff {
/// Take a managed version fo the persistent buff.
/// Allow to check if the buffer is valid or not before usage
/// Note that vs the [Self::take] function, you will lose sii
pub fn take_managed() -> Option<Self> {
Self::take().map(|b| Self {
magic: b.as_mut_ptr().cast::<u32>(),
buff: &mut b[core::mem::size_of::<u32>()..],
})
}
/// Steal a managed version for the persistent buff without check
/// See [Self::take_managed]
///
/// # Safety
/// Calling this function could allow to have two mutable reference to the same buffer.
/// Make sure to only have one reference at a time to avoid multiple mutable reference
pub unsafe fn steal_managed() -> Self {
let b = Self::steal();
Self {
magic: b.as_mut_ptr().cast::<u32>(),
buff: &mut b[core::mem::size_of::<u32>()..],
}
}
/// Get the raw persistent buff
pub fn take() -> Option<&'static mut [u8]> {
unsafe {
if PERSISTENT_BUFF_TAKEN.swap(true, Ordering::Relaxed) {
None
} else {
Some(Self::steal())
}
}
}
/// Steal the raw persistent buff.
/// Ignore if it was already taken or not.
///
/// # Safety
/// Calling this function could allow to have two mutable reference to the same buffer.
/// Make sure to only have one reference at a time to avoid multiple mutable reference
pub unsafe fn steal() -> &'static mut [u8] {
PERSISTENT_BUFF_TAKEN.store(true, Ordering::SeqCst);
extern "C" {
static mut _persistent_buff_start: u8;
static mut _persistent_buff_end: u8;
}
let start = &mut _persistent_buff_start as *mut u8;
let end = &mut _persistent_buff_end as *mut u8;
let len = end as usize - start as usize;
core::slice::from_raw_parts_mut(start, len)
}
/// Mark the persistent buffer with valid data in it
fn mark(&mut self) {
unsafe {
*self.magic = MAGIC_NUMBER;
}
}
/// Verify if the persistent buffer has valid data in it
fn check(&self) -> bool {
unsafe { *self.magic == MAGIC_NUMBER }
}
/// Check if the buffer is valid, if not call the provided closure
/// Then mark the buffer as valid and initialize it to a known state.
/// It's to make sure the data in it is always "valid" and not garbage after a powerloss.
pub fn validate<F>(&mut self, f: F) -> &mut [u8]
where
F: FnOnce(&mut [u8]),
{
if !self.check() {
f(self.buff)
}
self.mark();
self.buff
}
}