opentitanlib/rescue/
serial.rs1use anyhow::Result;
6use std::rc::Rc;
7use std::time::Duration;
8
9use crate::app::{TransportWrapper, UartRx};
10use crate::io::console::ConsoleExt;
11use crate::io::console::ext::{PassFail, PassFailResult};
12use crate::io::uart::Uart;
13use crate::regex;
14use crate::rescue::xmodem::Xmodem;
15use crate::rescue::{Rescue, RescueError, RescueMode};
16
17pub struct RescueSerial {
18 uart: Rc<dyn Uart>,
19 reset_delay: Duration,
20 enter_delay: Duration,
21}
22
23impl RescueSerial {
24 const ONE_SECOND: Duration = Duration::from_secs(1);
25 pub const REBOOT: RescueMode = RescueMode(u32::from_be_bytes(*b"REBO"));
26 pub const BAUD: RescueMode = RescueMode(u32::from_be_bytes(*b"BAUD"));
27 pub const WAIT: RescueMode = RescueMode(u32::from_be_bytes(*b"WAIT"));
28
29 const BAUD_115K: [u8; 4] = *b"115K";
30 const BAUD_230K: [u8; 4] = *b"230K";
31 const BAUD_460K: [u8; 4] = *b"460K";
32 const BAUD_921K: [u8; 4] = *b"921K";
33 const BAUD_1M33: [u8; 4] = *b"1M33";
34 const BAUD_1M50: [u8; 4] = *b"1M50";
35
36 pub fn new(uart: Rc<dyn Uart>) -> Self {
37 RescueSerial {
38 uart,
39 reset_delay: Duration::from_millis(50),
40 enter_delay: Duration::from_secs(5),
41 }
42 }
43}
44
45impl Rescue for RescueSerial {
46 fn enter(&self, transport: &TransportWrapper, reset_target: bool) -> Result<()> {
47 log::info!("Setting serial break to trigger rescue mode.");
48 self.uart.set_break(true)?;
49 if reset_target {
50 transport.reset_with_delay(UartRx::Clear, self.reset_delay)?;
51 }
52 (&self.uart)
53 .logged()
54 .wait_for_line("rescue:", self.enter_delay)?;
55 log::info!("Rescue triggered. clearing serial break.");
56 self.uart.set_break(false)?;
57 let _ = (&self.uart)
60 .logged()
61 .wait_for_line(PassFail("ok:", "error:"), Self::ONE_SECOND);
62 Ok(())
63 }
64
65 fn set_speed(&self, baud: u32) -> Result<u32> {
66 let symbol = match baud {
68 115200 => Self::BAUD_115K,
69 230400 => Self::BAUD_230K,
70 460800 => Self::BAUD_460K,
71 921600 => Self::BAUD_921K,
72 1333333 => Self::BAUD_1M33,
73 1500000 => Self::BAUD_1M50,
74 _ => return Err(RescueError::BadMode(format!("Unsupported badrate {baud}")).into()),
75 };
76
77 self.uart.write(&Self::BAUD.0.to_be_bytes())?;
80 self.uart.write(b"\r")?;
81 if let PassFailResult::Fail(result) = (&self.uart)
82 .logged()
83 .wait_for_line(PassFail("ok:", regex!("error:.*")), Self::ONE_SECOND)?
84 {
85 return Err(RescueError::BadMode(result[0].clone()).into());
86 }
87
88 self.uart.write(&symbol)?;
90 if let PassFailResult::Fail(result) = (&self.uart)
91 .logged()
92 .wait_for_line(PassFail("ok:", regex!("error:.*")), Self::ONE_SECOND)?
93 {
94 return Err(RescueError::BadMode(result[0].clone()).into());
95 }
96 let old = self.uart.get_baudrate()?;
98 self.uart.set_baudrate(baud)?;
99 Ok(old)
100 }
101
102 fn set_mode(&self, mode: RescueMode) -> Result<()> {
103 let mode = mode.0.to_be_bytes();
104 self.uart.write(&mode)?;
105 let enter = b'\r';
106 self.uart.write(std::slice::from_ref(&enter))?;
107 let mode = std::str::from_utf8(&mode)?;
108 (&self.uart)
109 .logged()
110 .wait_for_line(format!("mode: {mode}").as_str(), Self::ONE_SECOND)?;
111 if let PassFailResult::Fail(result) = (&self.uart)
112 .logged()
113 .wait_for_line(PassFail("ok:", regex!("error:.*")), Self::ONE_SECOND)?
114 {
115 return Err(RescueError::BadMode(result[0].clone()).into());
116 }
117 Ok(())
118 }
119
120 fn wait(&self) -> Result<()> {
121 self.set_mode(Self::WAIT)?;
122 Ok(())
123 }
124
125 fn reboot(&self) -> Result<()> {
126 self.set_mode(Self::REBOOT)?;
127 Ok(())
128 }
129
130 fn send(&self, data: &[u8]) -> Result<()> {
131 let xm = Xmodem::new();
132 xm.send(&*self.uart, data)?;
133 Ok(())
134 }
135
136 fn recv(&self) -> Result<Vec<u8>> {
137 let mut data = Vec::new();
138 let xm = Xmodem::new();
139 xm.receive(&*self.uart, &mut data)?;
140 Ok(data)
141 }
142}