use crate::context::UsbContext;
use crate::error::Result;
use crate::flash::Page;
use crate::target_handle::TargetHandle;
use std::iter::Enumerate;
use std::slice::{Chunks, ChunksMut};
pub trait Operation: Iterator<Item = Result<usize>> {
fn total(&self) -> usize;
fn execute(&mut self) -> Result<()> {
if let Some(Err(error)) = self.last() {
Err(error)
} else {
Ok(())
}
}
}
pub struct Erase<'a, T: UsbContext> {
handle: &'a mut TargetHandle<T>,
pages: Vec<Page>,
count: usize,
done: bool,
}
impl<T: UsbContext> Operation for Erase<'_, T> {
fn total(&self) -> usize {
self.count
}
}
impl<T: UsbContext> Iterator for Erase<'_, T> {
type Item = Result<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let page = self.pages.pop().unwrap();
if self.pages.is_empty() {
self.done = true;
}
Some(match self.handle.erase_page(page) {
Ok(()) => Ok(self.count - self.pages.len()),
Err(error) => {
self.done = true;
Err(error)
}
})
}
}
impl<'a, T: UsbContext> Erase<'a, T> {
pub(crate) fn pages(handle: &'a mut TargetHandle<T>, pages: &[Page]) -> Self {
Self {
handle,
done: pages.is_empty(),
pages: Vec::from(pages),
count: pages.len(),
}
}
pub(crate) fn area(handle: &'a mut TargetHandle<T>, start: u32, length: usize) -> Self {
let pages = if length == 0 {
Vec::new()
} else {
let first_page = Page::from_address(start);
let last_page = Page::from_address(start + length as u32 - 1);
(first_page.into()..=last_page.into())
.map(Page::from_index)
.collect()
};
Self {
handle,
done: pages.is_empty(),
count: pages.len(),
pages,
}
}
}
pub struct Program<'d, 'a, T: UsbContext> {
handle: &'a mut TargetHandle<T>,
address: u32,
chunks: Enumerate<Chunks<'d, u8>>,
length: usize,
chunk_size: usize,
done: bool,
}
impl<T: UsbContext> Operation for Program<'_, '_, T> {
fn total(&self) -> usize {
self.length
}
}
impl<T: UsbContext> Iterator for Program<'_, '_, T> {
type Item = Result<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if let Some((i, chunk)) = self.chunks.next() {
Some(
match self
.handle
.program_chunk(self.address + (i * self.chunk_size) as u32, chunk)
{
Ok(()) => Ok(i * self.chunk_size + chunk.len()),
Err(error) => {
self.done = true;
Err(error)
}
},
)
} else {
self.done = true;
None
}
}
}
impl<'d, 'a, T: UsbContext> Program<'d, 'a, T> {
pub(crate) fn at(handle: &'a mut TargetHandle<T>, data: &'d [u8], address: u32) -> Self {
let chunk_size = handle.max_program_chunk_size();
Self {
handle,
address,
chunk_size,
chunks: data.chunks(chunk_size).enumerate(),
length: data.len(),
done: data.is_empty(),
}
}
}
pub struct Read<'d, 'a, T: UsbContext> {
handle: &'a mut TargetHandle<T>,
address: u32,
chunks: Enumerate<ChunksMut<'d, u8>>,
length: usize,
chunk_size: usize,
done: bool,
}
impl<T: UsbContext> Operation for Read<'_, '_, T> {
fn total(&self) -> usize {
self.length
}
}
impl<T: UsbContext> Iterator for Read<'_, '_, T> {
type Item = Result<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if let Some((i, chunk)) = self.chunks.next() {
Some(
match self
.handle
.read_chunk(self.address + (i * self.chunk_size) as u32, chunk)
{
Ok(()) => Ok(i * self.chunk_size + chunk.len()),
Err(error) => {
self.done = true;
Err(error)
}
},
)
} else {
self.done = true;
None
}
}
}
impl<'d, 'a, T: UsbContext> Read<'d, 'a, T> {
pub(crate) fn at(handle: &'a mut TargetHandle<T>, buffer: &'d mut [u8], address: u32) -> Self {
let chunk_size = handle.max_read_chunk_size();
Self {
handle,
address,
chunk_size,
length: buffer.len(),
done: buffer.is_empty(),
chunks: buffer.chunks_mut(chunk_size).enumerate(),
}
}
}