stm32_uart_loader/
lib.rs

1//! STM32 Serial Bootloader.
2//!
3//! Base on AN3155
4
5use core::fmt::Debug;
6use core::marker::PhantomData;
7
8use log::{trace, debug, info, error};
9
10use nb::block;
11use thiserror::Error;
12
13use embedded_hal::blocking::delay::DelayMs;
14use embedded_hal::serial::{Read, Write};
15
16#[cfg(feature = "linux")]
17extern crate linux_embedded_hal;
18#[cfg(feature = "linux")]
19pub mod linux;
20
21pub mod protocol;
22use protocol::*;
23
24
25/// SerialPort trait wrapping embedded-hal with rts/dtr commands
26pub trait SerialPort<E>: Write<u8, Error = E> + Read<u8, Error = E> {
27    fn set_rts(&mut self, level: bool) -> Result<(), E>;
28    fn set_dtr(&mut self, level: bool) -> Result<(), E>;
29}
30
31#[derive(Error, Clone, PartialEq, Debug)]
32pub enum Error<SerialError: Debug> {
33    #[error("Serial device error: {0:?}")]
34    Serial(SerialError),
35    #[error("Nack")]
36    Nack,
37    #[error("NoAck")]
38    NoAck,
39    #[error("Timeout")]
40    Timeout,
41    #[error("InvalidResponse")]
42    InvalidResponse,
43    #[error("BufferLength")]
44    BufferLength,
45    #[error("Io error: {0:?}")]
46    Io(std::io::ErrorKind),
47}
48
49impl<SerialError: Debug> From<SerialError> for Error<SerialError> {
50    fn from(e: SerialError) -> Self {
51        Self::Serial(e)
52    }
53}
54
55#[derive(Clone, PartialEq, Debug)]
56#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))]
57pub struct Options {
58    /// Do not reset the device on connection
59    #[cfg_attr(feature = "structopt", structopt(long))]
60    pub no_reset: bool,
61
62    /// Timeout to wait for bootloader responses
63    #[cfg_attr(feature = "structopt", structopt(long, default_value = "100"))]
64    pub response_timeout_ms: u32,
65
66    /// Period to poll for bootloader responses
67    #[cfg_attr(feature = "structopt", structopt(long, default_value = "10"))]
68    pub poll_delay_ms: u32,
69
70    /// Period to wait for bootloader init before sending init character
71    #[cfg_attr(feature = "structopt", structopt(long, default_value = "100"))]
72    pub init_delay_ms: u32,
73
74    /// Disable progress bars during operations
75    #[cfg_attr(feature = "structopt", structopt(long))]
76    pub no_progress: bool,
77}
78
79impl Default for Options {
80    fn default() -> Self {
81        Self {
82            no_reset: false,
83            no_progress: false,
84            response_timeout_ms: 100,
85            poll_delay_ms: 10,
86            init_delay_ms: 100,
87        }
88    }
89}
90
91pub struct Programmer<P, D, E> {
92    options: Options,
93    port: P,
94    delay: D,
95    _err: PhantomData<E>,
96}
97
98impl<P, D, E> Programmer<P, D, E>
99where
100    P: SerialPort<E>,
101    D: DelayMs<u32>,
102    E: core::fmt::Debug,
103{
104    /// Create a new programmer instance and connect to the attached bootloader
105    pub fn new(port: P, delay: D, options: Options) -> Result<Self, Error<E>> {
106        let mut s = Self {
107            options,
108            port,
109            delay,
110            _err: PhantomData,
111        };
112
113        s.init()?;
114
115        Ok(s)
116    }
117
118    // Initialise the programmer/bootloader
119    fn init(&mut self) -> Result<(), Error<E>> {
120        // First, reset device
121        debug!("Resetting device");
122
123        self.reset(true)?;
124
125        debug!("Sending discovery character");
126
127        // Then, send discovery character
128        block!(self.port.write(UART_DISC)).unwrap();
129        block!(self.port.flush()).unwrap();
130
131        // Wait for a response
132        debug!("Awaiting bootloader response");
133        let _ = self.await_ack();
134
135        // Wait for bootloader to think a little
136        self.delay.delay_ms(100);
137
138        // Read info
139        debug!("Reading bootloader info");
140        let version = self.info()?;
141        debug!("Bootloader version: 0x{:02x}", version);
142
143        self.delay.delay_ms(100);
144
145        // Return ok
146        Ok(())
147    }
148
149    /// Fetch bootloader info byte
150    // TODO: there's more useful info than just this?
151    pub fn info(&mut self) -> Result<u8, Error<E>> {
152        let mut data = [0u8; 12];
153
154        // Write command
155        self.write_cmd(Command::Get)?;
156
157        // Await ack
158        self.await_ack()?;
159
160        // Read comand length
161        let n = self.read_char()? as usize + 1;
162
163        debug!("Reading {} bytes", n);
164
165        if data.len() < n {
166            error!("RX buffer too short");
167            return Err(Error::BufferLength);
168        }
169
170        // Read data
171        for i in 0..n {
172            data[i] = self.read_char()?;
173        }
174
175        // Await final ack
176        self.await_ack()?;
177
178        debug!("Received: 0x{:02x?}", &data[..n]);
179
180        Ok(data[0])
181    }
182
183    /// Erase pages by page offset and count
184    pub fn erase(&mut self, page_offset: u8, page_count: u8) -> Result<(), Error<E>> {
185
186        debug!("Erasing {} pages from index {}", page_count, page_offset);
187        let pages: Vec<u8> = (page_count..page_offset+page_count).collect();
188
189        self.erase_pages(&pages)
190    }
191
192    /// Erase pages by page number
193    pub fn erase_pages(&mut self, pages: &[u8]) -> Result<(), Error<E>> {
194        // Write command
195        self.write_cmd(Command::Erase)?;
196        self.await_ack()?;
197
198        // Write number of pages
199        let len = (pages.len() - 1) as u8;
200        block!(self.port.write(len))?;
201
202        // Write page list
203        self.write_bytes_csum(pages)?;
204
205        self.await_ack()
206    }
207
208    /// Erase the entire flash
209    pub fn erase_all(&mut self) -> Result<(), Error<E>> {
210        // Write command
211        self.write_cmd(Command::Erase)?;
212        self.await_ack()?;
213
214        self.write_bytes(&[0xFF, 0x00])?;
215        self.await_ack()?;
216
217        Ok(())
218    }
219
220    /// Read memory from the device
221    pub fn read(&mut self, addr: u32, data: &mut [u8]) -> Result<(), Error<E>> {
222        let mut index = 0;
223        
224        // Setup progress bar _if_ enabled
225        #[cfg(feature="indicatif")]
226        let mut p = match !self.options.no_progress {
227            true => {
228                let pb = indicatif::ProgressBar::new(data.len() as u64);
229
230                pb.set_style(indicatif::ProgressStyle::default_bar()
231                    .template("{spinner:.green} [{elapsed_precise}] [{bar:80.cyan/blue}] {bytes}/{total_bytes} ({eta})")
232                    .progress_chars("#>-"));
233
234                Some(pb)
235            },
236            _ => None,
237        };
238
239        for chunk in data.chunks_mut(MAX_CHUNK as usize) {
240            debug!("Read chunk at 0x{:08x}, length: {}", addr + index as u32, chunk.len());
241
242            self.read_mem_block(addr + index as u32, &mut chunk[..])?;
243
244            index += chunk.len();
245
246            // Update progress bar (if enabled)
247            #[cfg(feature="indicatif")]
248            if let Some(p) = &mut p {
249                p.inc(chunk.len() as u64)
250            }
251        }
252
253        Ok(())
254    }
255
256    fn read_mem_block(&mut self, addr: u32, data: &mut [u8]) -> Result<(), Error<E>> {
257        assert!(data.len() <= 256, "block size must be less than 256 bytes");
258
259        // Write read command and await ack
260        self.write_cmd(Command::ReadMemory)?;
261        self.await_ack()?;
262        
263
264        // Write start address + xor checksum and await ack
265        let addr = [(addr >> 24) as u8, (addr >> 16) as u8, (addr >> 8) as u8, addr as u8];
266        let addr_csum = addr[0] ^ addr[1] ^ addr[2] ^ addr[3];
267
268        for a in &addr {
269            block!(self.port.write(*a))?;
270        }
271        block!(self.port.write(addr_csum))?;
272        block!(self.port.flush())?;
273
274        self.await_ack()?;
275
276
277        // Write read length and checksum and await ack
278        let len = (data.len() - 1) as u8;
279        self.write_bytes(&[len, !len])?;
280
281        self.await_ack()?;
282
283        // Read response data
284        for i in 0..data.len() {
285            data[i] = self.read_char()?;
286        }
287
288        Ok(())
289    }
290
291    /// Write memory to the device
292    pub fn write(&mut self, addr: u32, data: &[u8]) -> Result<(), Error<E>> {
293        let mut index = 0;
294
295        // Setup progress bar _if_ enabled
296        #[cfg(feature="indicatif")]
297        let mut p = match !self.options.no_progress {
298            true => {
299                let pb = indicatif::ProgressBar::new(data.len() as u64);
300
301                pb.set_style(indicatif::ProgressStyle::default_bar()
302                    .template("{spinner:.green} [{elapsed_precise}] [{bar:80.cyan/blue}] {bytes}/{total_bytes} ({eta})")
303                    .progress_chars("#>-"));
304
305                Some(pb)
306            },
307            _ => None,
308        };
309
310        for chunk in data.chunks(MAX_CHUNK as usize) {
311            debug!("Write chunk at 0x{:08x}, length: {}", addr + index as u32, chunk.len());
312
313            self.write_mem_block(addr + index as u32, &chunk[..])?;
314
315            index += chunk.len();
316
317            // Update progress bar (if enabled)
318            #[cfg(feature="indicatif")]
319            if let Some(p) = &mut p {
320                p.inc(chunk.len() as u64)
321            }
322        }
323
324        Ok(())
325    }
326
327    fn write_mem_block(&mut self, addr: u32, data: &[u8]) -> Result<(), Error<E>> {
328        assert!(data.len() <= 256, "block size must be less than 256 bytes");
329
330        // Write read command and await ack
331        self.write_cmd(Command::WriteMemory)?;
332        self.await_ack()?;
333        
334
335        // Write start address + xor checksum and await ack
336        let addr = [(addr >> 24) as u8, (addr >> 16) as u8, (addr >> 8) as u8, addr as u8];
337        let addr_csum = addr[0] ^ addr[1] ^ addr[2] ^ addr[3];
338
339        for a in &addr {
340            block!(self.port.write(*a))?;
341        }
342        block!(self.port.write(addr_csum))?;
343        block!(self.port.flush())?;
344
345        self.await_ack()?;
346
347
348        // Set write length and checksum and await ack
349        let len = (data.len() - 1) as u8;
350        let mut data_csum = len;
351
352        block!(self.port.write(len))?;
353        for d in data {
354            data_csum ^= *d;
355            block!(self.port.write(*d))?;
356        }
357        block!(self.port.write(data_csum))?;
358
359        self.await_ack()?;
360
361
362        Ok(())
363    }
364
365    /// Reset the device using RTS while asserting DTR entering the bootloading or application
366    pub fn reset(&mut self, bootloader: bool) -> Result<(), Error<E>> {
367        // Assert RTS to reset the device
368        self.port.set_rts(true)?;
369
370        // Wait a moment for the device to turn off
371        self.delay.delay_ms(10u32);
372
373        if bootloader {
374            // DTR signals to use bootloader
375            self.port.set_dtr(true)?;
376        }
377
378        // RTS re-enables device
379        self.port.set_rts(false)?;
380
381        // Wait for bootloader or app to start
382        self.delay.delay_ms(self.options.init_delay_ms);
383
384        if bootloader {
385            // De-assert DTR
386            self.port.set_dtr(false)?;
387        }
388
389        Ok(())
390    }
391
392    /// Fetch device chip ID (not-working)
393    pub fn chip_id(&mut self) -> Result<u16, Error<E>> {
394        // Write GetID command
395        self.write_cmd(Command::GetId)?;
396        
397        // Await ACK
398        self.await_ack()?;
399
400        // Read N (static sized)
401        let n = self.read_char()? as usize + 1;
402
403        debug!("Reading {} byte chip ID", n);
404
405        // Read chip ID
406        let mut v: u16 = 0;
407        for i in 0..n {
408            let c = self.read_char()?;
409            v |= (c as u16) << (i * 8);
410        }
411
412        // Await ACK
413        self.await_ack()?;
414
415        Ok(v)
416    }
417
418    /// Write a bootloader command to the device
419    pub fn write_cmd(&mut self, command: Command) -> Result<(), Error<E>> {
420        // Write command
421        let c1 = command.clone() as u8;
422        let c2 = !c1;
423
424        debug!("Writing command {:?} [0x{:02x}, 0x{:02x}]", command, c1, c2);
425
426        block!(self.port.write(c1))?;
427        block!(self.port.write(c2))?;
428        block!(self.port.flush())?;
429
430        Ok(())
431    }
432
433    pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error<E>> {
434
435        debug!("Writing bytes: 0x{:02x?}", data);
436
437        for d in data {
438            block!(self.port.write(*d))?;
439        }
440
441        block!(self.port.flush())?;
442
443        Ok(())
444    }
445
446    /// Write data with xor checksum
447    pub fn write_bytes_csum(&mut self, data: &[u8]) -> Result<(), Error<E>> {
448        let mut csum = 0x00;
449        for d in data {
450            csum ^= *d;
451        }
452
453        info!("Writing data with checksum: {:02x?} ({:02x})", data, csum);
454
455        for d in data {
456            block!(self.port.write(*d))?;
457        }
458
459        block!(self.port.write(csum))?;
460        block!(self.port.flush())?;
461
462        Ok(())
463    }
464
465    /// Read a single character from the device
466    pub fn read_char(&mut self) -> Result<u8, Error<E>> {
467        let mut t = 0;
468
469        loop {
470            // Attempt to read from serial port
471            match self.port.read() {
472                Err(nb::Error::WouldBlock) => (),
473                Err(nb::Error::Other(e)) => return Err(e.into()),
474                Ok(v) => return Ok(v)
475            };
476
477            // Wait for delay period
478            self.delay.delay_ms(self.options.poll_delay_ms);
479            t += self.options.poll_delay_ms;
480
481            if t > self.options.response_timeout_ms {
482                error!("Receive timeout");
483                return Err(Error::Timeout);
484            }
485        }
486    }
487
488    /// Await an ack from the bootloader
489    fn await_ack(&mut self) -> Result<(), Error<E>> {
490        let v = self.read_char()?;
491        match v {
492            UART_ACK => {
493                trace!("Received ACK!");
494                Ok(())
495            },
496            UART_NACK => {
497                trace!("Received NACK?!");
498                Err(Error::Nack)
499            },
500            _ => {
501                error!("Unexpected response: 0x{:02x}", v);
502                Err(Error::InvalidResponse)
503            }
504        }
505    }
506}