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
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! The Flash Controller interface with hardware
use crate::error_codes::ErrorCode;
/// Implementation required for the flash controller hardware. This
/// should read, write and erase flash from the hardware using the
/// flash controller.
///
/// This is the public trait for the Flash controller implementation.
///
/// The size of the regions (pages) must be the smallest size that can be
/// erased in a single operation. This is specified as the constant `S`
/// when implementing `FlashController` and `TicKV` and it must match
/// the length of the `read_buffer`.
///
/// The start and end address of the FlashController must be aligned
/// to the size of regions.
/// All `region_number`s and `address`es are offset from zero. If you
/// want to use flash that doesn't start at zero, or is a partition
/// offset from the start of flash you will need to add that offset
/// to the values in your implementation.
///
/// The boiler plate for an implementation will look something like this
///
/// ```rust
/// use tickv::error_codes::ErrorCode;
/// use tickv::flash_controller::FlashController;
///
/// #[derive(Default)]
/// struct FlashCtrl {}
///
/// impl FlashCtrl {
/// fn new() -> Self {
/// Self { /* fields */ }
/// }
/// }
///
/// impl FlashController<1024> for FlashCtrl {
/// fn read_region(&self, region_number: usize, buf: &mut [u8; 1024]) -> Result<(), ErrorCode> {
/// unimplemented!()
/// }
///
/// fn write(&self, address: usize, buf: &[u8]) -> Result<(), ErrorCode> {
/// unimplemented!()
/// }
///
/// fn erase_region(&self, region_number: usize) -> Result<(), ErrorCode> {
/// unimplemented!()
/// }
/// }
/// ```
pub trait FlashController<const S: usize> {
/// This function must read the data from the flash region specified by
/// `region_number` into `buf`. The length of the data read should be the
/// same length as buf.
///
/// On success it should return nothing, on failure it
/// should return ErrorCode::ReadFail.
///
/// If the read operation is to be complete asynchronously then
/// `read_region()` can return `ErrorCode::ReadNotReady(region_number)`.
/// By returning `ErrorCode::ReadNotReady(region_number)`
/// `read_region()` can indicate that the operation should be retried in
/// the future.
/// After running the `continue_()` functions after a async
/// `read_region()` has returned `ErrorCode::ReadNotReady(region_number)`
/// the `read_region()` function will be called again and this time should
/// return the data.
fn read_region(&self, region_number: usize, buf: &mut [u8; S]) -> Result<(), ErrorCode>;
/// This function must write the length of `buf` to the specified address
/// in flash.
/// If the length of `buf` is smaller then the minimum supported write size
/// the implementation can write a larger value. This should be done by first
/// reading the value, making the changed from `buf` and then writing it back.
///
/// On success it should return nothing, on failure it
/// should return ErrorCode::WriteFail.
///
/// If the write operation is to be complete asynchronously then
/// `write()` can return `ErrorCode::WriteNotReady(region_number)`.
/// By returning `ErrorCode::WriteNotReady(region_number)`
/// `read_region()` can indicate that the operation should be retried in
/// the future. Note that that region will not be written
/// again so the write must occur otherwise the operation fails.
fn write(&self, address: usize, buf: &[u8]) -> Result<(), ErrorCode>;
/// This function must erase the region specified by `region_number`.
///
/// On success it should return nothing, on failure it
/// should return ErrorCode::WriteFail.
///
/// If the erase is going to happen asynchronously then this should return
/// `EraseNotReady(region_number)`. Note that that region will not be erased
/// again so the erasure must occur otherwise the operation fails.
fn erase_region(&self, region_number: usize) -> Result<(), ErrorCode>;
}