tickv/
flash_controller.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! The Flash Controller interface with hardware
6
7use crate::error_codes::ErrorCode;
8
9/// Implementation required for the flash controller hardware. This
10/// should read, write and erase flash from the hardware using the
11/// flash controller.
12///
13/// This is the public trait for the Flash controller implementation.
14///
15/// The size of the regions (pages) must be the smallest size that can be
16/// erased in a single operation. This is specified as the constant `S`
17/// when implementing `FlashController` and `TicKV` and it must match
18/// the length of the `read_buffer`.
19///
20/// The start and end address of the FlashController must be aligned
21/// to the size of regions.
22/// All `region_number`s and `address`es are offset from zero. If you
23/// want to use flash that doesn't start at zero, or is a partition
24/// offset from the start of flash you will need to add that offset
25/// to the values in your implementation.
26///
27/// The boiler plate for an implementation will look something like this
28///
29/// ```rust
30/// use tickv::error_codes::ErrorCode;
31/// use tickv::flash_controller::FlashController;
32///
33/// #[derive(Default)]
34/// struct FlashCtrl {}
35///
36/// impl FlashCtrl {
37///     fn new() -> Self {
38///         Self { /* fields */ }
39///     }
40/// }
41///
42/// impl FlashController<1024> for FlashCtrl {
43///     fn read_region(&self, region_number: usize, buf: &mut [u8; 1024]) -> Result<(), ErrorCode> {
44///         unimplemented!()
45///     }
46///
47///     fn write(&self, address: usize, buf: &[u8]) -> Result<(), ErrorCode> {
48///         unimplemented!()
49///     }
50///
51///     fn erase_region(&self, region_number: usize) -> Result<(), ErrorCode> {
52///         unimplemented!()
53///     }
54/// }
55/// ```
56pub trait FlashController<const S: usize> {
57    /// This function must read the data from the flash region specified by
58    /// `region_number` into `buf`. The length of the data read should be the
59    /// same length as buf.
60    ///
61    /// On success it should return nothing, on failure it
62    /// should return ErrorCode::ReadFail.
63    ///
64    /// If the read operation is to be complete asynchronously then
65    /// `read_region()` can return `ErrorCode::ReadNotReady(region_number)`.
66    /// By returning `ErrorCode::ReadNotReady(region_number)`
67    /// `read_region()` can indicate that the operation should be retried in
68    /// the future.
69    /// After running the `continue_()` functions after a async
70    /// `read_region()` has returned `ErrorCode::ReadNotReady(region_number)`
71    /// the `read_region()` function will be called again and this time should
72    /// return the data.
73    fn read_region(&self, region_number: usize, buf: &mut [u8; S]) -> Result<(), ErrorCode>;
74
75    /// This function must write the length of `buf` to the specified address
76    /// in flash.
77    /// If the length of `buf` is smaller then the minimum supported write size
78    /// the implementation can write a larger value. This should be done by first
79    /// reading the value, making the changed from `buf` and then writing it back.
80    ///
81    /// On success it should return nothing, on failure it
82    /// should return ErrorCode::WriteFail.
83    ///
84    /// If the write operation is to be complete asynchronously then
85    /// `write()` can return `ErrorCode::WriteNotReady(region_number)`.
86    /// By returning `ErrorCode::WriteNotReady(region_number)`
87    /// `read_region()` can indicate that the operation should be retried in
88    /// the future. Note that that region will not be written
89    /// again so the write must occur otherwise the operation fails.
90    fn write(&self, address: usize, buf: &[u8]) -> Result<(), ErrorCode>;
91
92    /// This function must erase the region specified by `region_number`.
93    ///
94    /// On success it should return nothing, on failure it
95    /// should return ErrorCode::WriteFail.
96    ///
97    /// If the erase is going to happen asynchronously then this should return
98    /// `EraseNotReady(region_number)`. Note that that region will not be erased
99    /// again so the erasure must occur otherwise the operation fails.
100    fn erase_region(&self, region_number: usize) -> Result<(), ErrorCode>;
101}