use crate::domain::{
bad_block::BadBlockTable, Address, BadBlockStrategy, FlashOperation, OobMode, Progress,
ReadRequest,
};
use crate::error::{Error, Result};
pub struct VerifyParams<'a> {
pub address: u32,
pub data: &'a [u8],
pub use_ecc: bool,
pub ignore_ecc_errors: bool,
pub oob_mode: OobMode,
pub bad_block_strategy: BadBlockStrategy,
pub bbt: Option<BadBlockTable>,
pub retry_count: u32,
}
pub struct VerifyFlashUseCase<F: FlashOperation> {
flash: F,
}
impl<F: FlashOperation> VerifyFlashUseCase<F> {
pub fn new(flash: F) -> Self {
Self { flash }
}
pub fn execute<P>(&mut self, params: VerifyParams, on_progress: P) -> Result<()>
where
P: Fn(Progress),
{
let request = ReadRequest {
address: Address::new(params.address),
length: params.data.len() as u32,
use_ecc: params.use_ecc,
ignore_ecc_errors: params.ignore_ecc_errors,
oob_mode: params.oob_mode,
bad_block_strategy: params.bad_block_strategy,
bbt: params.bbt,
retry_count: params.retry_count,
};
let actual_data = self.flash.read(request, &on_progress)?;
if actual_data == params.data {
Ok(())
} else {
for (i, (a, e)) in actual_data.iter().zip(params.data.iter()).enumerate() {
if a != e {
return Err(Error::VerificationFailed {
address: params.address + i as u32,
expected: *e,
actual: *a,
});
}
}
Err(Error::InvalidParameter("Data lengths differ".to_string()))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::{EraseRequest, FlashOperation, WriteRequest};
struct MockFlashReader {
mock_data: Vec<u8>,
}
impl MockFlashReader {
fn new(data: Vec<u8>) -> Self {
Self { mock_data: data }
}
}
impl FlashOperation for MockFlashReader {
fn read(
&mut self,
_request: ReadRequest,
_on_progress: &dyn Fn(Progress),
) -> Result<Vec<u8>> {
Ok(self.mock_data.clone())
}
fn write(&mut self, _request: WriteRequest, _on_progress: &dyn Fn(Progress)) -> Result<()> {
Ok(())
}
fn erase(&mut self, _request: EraseRequest, _on_progress: &dyn Fn(Progress)) -> Result<()> {
Ok(())
}
}
#[test]
fn test_verify_success() {
let data = vec![1, 2, 3, 4];
let flash = MockFlashReader::new(data.clone());
let mut use_case = VerifyFlashUseCase::new(flash);
let params = VerifyParams {
address: 0,
data: &data,
use_ecc: true,
ignore_ecc_errors: false,
oob_mode: OobMode::None,
bad_block_strategy: BadBlockStrategy::Fail,
bbt: None,
retry_count: 0,
};
let result = use_case.execute(params, |_| {});
assert!(result.is_ok());
}
#[test]
fn test_verify_failure() {
let actual_data = vec![1, 2, 0, 4]; let expected_data = vec![1, 2, 3, 4];
let flash = MockFlashReader::new(actual_data);
let mut use_case = VerifyFlashUseCase::new(flash);
let params = VerifyParams {
address: 0x100,
data: &expected_data,
use_ecc: true,
ignore_ecc_errors: false,
oob_mode: OobMode::None,
bad_block_strategy: BadBlockStrategy::Fail,
bbt: None,
retry_count: 0,
};
let result = use_case.execute(params, |_| {});
assert!(result.is_err());
match result {
Err(Error::VerificationFailed {
address,
expected,
actual,
}) => {
assert_eq!(address, 0x100 + 2); assert_eq!(expected, 3);
assert_eq!(actual, 0);
}
_ => panic!("Expected VerificationFailed error"),
}
}
}