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
use super::*;
use std::convert::TryFrom;
use std::io::Cursor;
use std::prelude::v1::*;
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub struct DfuSync<IO, E>
where
IO: DfuIo<Read = usize, Write = usize, Reset = (), Error = E>,
E: From<std::io::Error> + From<Error>,
{
dfu: DfuSansIo<IO>,
buffer: Vec<u8>,
progress: Option<Box<dyn FnMut(usize)>>,
}
impl<IO, E> DfuSync<IO, E>
where
IO: DfuIo<Read = usize, Write = usize, Reset = (), Error = E>,
E: From<std::io::Error> + From<Error>,
{
pub fn new(io: IO, address: u32) -> Self {
let transfer_size = io.functional_descriptor().transfer_size as usize;
Self {
dfu: DfuSansIo::new(io, address),
buffer: vec![0x00; transfer_size],
progress: None,
}
}
pub fn with_progress(&mut self, progress: impl FnMut(usize) + 'static) -> &mut Self {
self.progress = Some(Box::new(progress));
self
}
pub fn override_address(&mut self, address: u32) -> &mut Self {
self.dfu.address = address;
self
}
}
impl<IO, E> DfuSync<IO, E>
where
IO: DfuIo<Read = usize, Write = usize, Reset = (), Error = E>,
E: From<std::io::Error> + From<Error>,
{
pub fn download_from_slice(&mut self, slice: &[u8]) -> Result<(), IO::Error> {
let length = slice.len();
let cursor = Cursor::new(slice);
self.download(
cursor,
u32::try_from(length).map_err(|_| Error::OutOfCapabilities)?,
)
}
pub fn download<R: std::io::Read>(&mut self, reader: R, length: u32) -> Result<(), IO::Error> {
use std::io::BufRead;
let transfer_size = self.dfu.io.functional_descriptor().transfer_size as usize;
let mut reader = std::io::BufReader::with_capacity(transfer_size, reader);
let buffer = reader.fill_buf()?;
if buffer.is_empty() {
return Ok(());
}
macro_rules! wait_status {
($cmd:expr) => {{
let mut cmd = $cmd;
loop {
cmd = match cmd.next() {
get_status::Step::Break(cmd) => break cmd,
get_status::Step::Wait(cmd, poll_timeout) => {
std::thread::sleep(std::time::Duration::from_millis(poll_timeout));
let (cmd, n) = cmd.get_status(&mut self.buffer)?;
cmd.chain(&self.buffer[..n])?
}
get_status::Step::ManifestWaitReset(None) => return Ok(()),
get_status::Step::ManifestWaitReset(Some(cmd)) => {
let (_, res) = cmd.reset();
res?;
return Ok(());
}
};
}
}};
}
let cmd = self.dfu.download(length)?;
let (cmd, n) = cmd.get_status(&mut self.buffer)?;
let (cmd, _) = cmd.chain(&self.buffer[..n])??;
let (cmd, n) = cmd.get_status(&mut self.buffer)?;
let mut download_loop = cmd.chain(&self.buffer[..n])??;
loop {
download_loop = match download_loop.next() {
download::Step::Break => break,
download::Step::Erase(cmd) => {
let (cmd, _) = cmd.erase()?;
wait_status!(cmd)
}
download::Step::SetAddress(cmd) => {
let (cmd, _) = cmd.set_address()?;
wait_status!(cmd)
}
download::Step::DownloadChunk(cmd) => {
let chunk = reader.fill_buf()?;
let (cmd, n) = cmd.download(chunk)?;
reader.consume(n);
if let Some(progress) = self.progress.as_mut() {
progress(n);
}
wait_status!(cmd)
}
}
}
Ok(())
}
pub fn download_all<R: std::io::Read + std::io::Seek>(
&mut self,
mut reader: R,
) -> Result<(), IO::Error> {
let length = u32::try_from(reader.seek(std::io::SeekFrom::End(0))?)
.map_err(|_| Error::MaximumTransferSizeExceeded)?;
reader.seek(std::io::SeekFrom::Start(0))?;
self.download(reader, length)
}
}