opentitanlib/transport/chip_whisperer/
mod.rs1use anyhow::{Result, ensure};
6use serde_annotate::Annotate;
7use serialport::SerialPortType;
8use std::any::Any;
9use std::cell::RefCell;
10use std::collections::HashMap;
11use std::collections::hash_map::Entry;
12use std::rc::Rc;
13
14use crate::io::gpio::GpioPin;
15use crate::io::spi::Target;
16use crate::io::uart::{Uart, UartError};
17use crate::transport::common::fpga::{ClearBitstream, FpgaProgram};
18use crate::transport::common::uart::{SerialPortUart, SoftwareFlowControl};
19use crate::transport::{
20 Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
21};
22use crate::util::parse_int::ParseInt;
23use board::Board;
24
25pub mod board;
26pub mod gpio;
27pub mod spi;
28pub mod usb;
29
30#[derive(Default)]
31struct Inner {
32 spi: Option<Rc<dyn Target>>,
33 gpio: HashMap<String, Rc<dyn GpioPin>>,
34 uart: HashMap<u32, Rc<dyn Uart>>,
35}
36
37pub struct ChipWhisperer<B: Board> {
38 pub(crate) device: Rc<RefCell<usb::Backend<B>>>,
39 uart_override: Vec<String>,
40 inner: RefCell<Inner>,
41}
42
43impl<B: Board> ChipWhisperer<B> {
44 pub fn new(
45 usb_vid: Option<u16>,
46 usb_pid: Option<u16>,
47 usb_serial: Option<&str>,
48 uart_override: &[&str],
49 ) -> anyhow::Result<Self> {
50 let board = ChipWhisperer {
51 device: Rc::new(RefCell::new(usb::Backend::new(
52 usb_vid, usb_pid, usb_serial,
53 )?)),
54 uart_override: uart_override.iter().map(|s| s.to_string()).collect(),
55 inner: RefCell::default(),
56 };
57 Ok(board)
58 }
59
60 fn open_uart(&self, instance: u32) -> Result<SoftwareFlowControl<SerialPortUart>> {
61 if self.uart_override.is_empty() {
62 let usb = self.device.borrow();
63 let serial_number = usb.get_serial_number();
64
65 let mut ports = serialport::available_ports()
66 .map_err(|e| UartError::EnumerationError(e.to_string()))?;
67 ports.retain(|port| {
68 if let SerialPortType::UsbPort(info) = &port.port_type
69 && info.serial_number.as_deref() == Some(serial_number)
70 {
71 return true;
72 }
73 false
74 });
75 ports.sort_by(|a, b| b.port_name.cmp(&a.port_name));
78
79 let port = ports.get(instance as usize).ok_or_else(|| {
80 TransportError::InvalidInstance(TransportInterfaceType::Uart, instance.to_string())
81 })?;
82 Ok(SoftwareFlowControl::new(SerialPortUart::open(
83 &port.port_name,
84 B::UART_BAUD,
85 )?))
86 } else {
87 let instance = instance as usize;
88 ensure!(
89 instance < self.uart_override.len(),
90 TransportError::InvalidInstance(TransportInterfaceType::Uart, instance.to_string())
91 );
92 Ok(SoftwareFlowControl::new(SerialPortUart::open(
93 &self.uart_override[instance],
94 B::UART_BAUD,
95 )?))
96 }
97 }
98}
99
100impl<B: Board + 'static> Transport for ChipWhisperer<B> {
101 fn capabilities(&self) -> Result<Capabilities> {
102 Ok(Capabilities::new(
103 Capability::SPI | Capability::GPIO | Capability::UART | Capability::UART_NONBLOCKING,
104 ))
105 }
106
107 fn uart(&self, instance: &str) -> Result<Rc<dyn Uart>> {
108 let mut inner = self.inner.borrow_mut();
109 let instance = u32::from_str(instance).ok().ok_or_else(|| {
110 TransportError::InvalidInstance(TransportInterfaceType::Uart, instance.to_string())
111 })?;
112 let uart = match inner.uart.entry(instance) {
113 Entry::Vacant(v) => {
114 let u = v.insert(Rc::new(self.open_uart(instance)?));
115 Rc::clone(u)
116 }
117 Entry::Occupied(o) => Rc::clone(o.get()),
118 };
119 Ok(uart)
120 }
121
122 fn gpio_pin(&self, pinname: &str) -> Result<Rc<dyn GpioPin>> {
123 let mut inner = self.inner.borrow_mut();
124 Ok(match inner.gpio.entry(pinname.to_string()) {
125 Entry::Vacant(v) => {
126 let u = v.insert(Rc::new(gpio::Pin::open(
127 Rc::clone(&self.device),
128 pinname.to_string(),
129 )?));
130 Rc::clone(u)
131 }
132 Entry::Occupied(o) => Rc::clone(o.get()),
133 })
134 }
135
136 fn spi(&self, instance: &str) -> Result<Rc<dyn Target>> {
137 ensure!(
138 instance == "0",
139 TransportError::InvalidInstance(TransportInterfaceType::Spi, instance.to_string())
140 );
141 let mut inner = self.inner.borrow_mut();
142 if inner.spi.is_none() {
143 inner.spi = Some(Rc::new(spi::Spi::open(Rc::clone(&self.device))?));
144 }
145 Ok(Rc::clone(inner.spi.as_ref().unwrap()))
146 }
147
148 fn dispatch(&self, action: &dyn Any) -> Result<Option<Box<dyn Annotate>>> {
149 if let Some(fpga_program) = action.downcast_ref::<FpgaProgram>() {
150 log::info!("Programming the FPGA bitstream.");
152 let usb = self.device.borrow();
153 usb.spi1_enable(false)?;
154 usb.fpga_program(&fpga_program.bitstream, fpga_program.progress.as_ref())?;
155 Ok(None)
156 } else if action.downcast_ref::<ResetSam3x>().is_some() {
157 self.device.borrow().reset_sam3x()?;
158 Ok(None)
159 } else if action.downcast_ref::<SetPll>().is_some() {
160 const TARGET_FREQ: u32 = 100_000_000;
161 let usb = self.device.borrow();
162 usb.pll_enable(true)?;
163 usb.pll_out_freq_set(1, TARGET_FREQ)?;
164 usb.pll_out_freq_set(2, TARGET_FREQ)?;
165 usb.pll_out_enable(0, false)?;
166 usb.pll_out_enable(1, true)?;
167 usb.pll_out_enable(2, false)?;
168 usb.pll_write_defaults()?;
169 Ok(None)
170 } else if action.downcast_ref::<ClearBitstream>().is_some() {
171 let usb = self.device.borrow();
172 usb.spi1_enable(false)?;
173 usb.clear_bitstream()?;
174 Ok(None)
175 } else if action.downcast_ref::<GetSam3xFwVersion>().is_some() {
176 let usb = self.device.borrow();
177 Ok(Some(Box::new(usb.get_firmware_version()?)))
178 } else {
179 Err(TransportError::UnsupportedOperation.into())
180 }
181 }
182}
183
184pub struct SetPll {}
186
187pub struct ResetSam3x {}
189
190pub struct GetSam3xFwVersion {}