opentitanlib/transport/ti50emulator/
mod.rs1use anyhow::{Context, Result};
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::fs;
9use std::path::{Path, PathBuf};
10use std::process;
11use std::rc::{Rc, Weak};
12use std::time::{SystemTime, UNIX_EPOCH};
13use std::vec::Vec;
14
15use crate::io::emu::Emulator;
16use crate::io::gpio::GpioPin;
17use crate::io::i2c::Bus;
18use crate::io::spi::Target;
19use crate::io::uart::Uart;
20use crate::transport::{
21 Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
22};
23
24mod emu;
25mod gpio;
26mod i2c;
27mod uart;
28
29use crate::transport::ti50emulator::emu::{EmulatorImpl, EmulatorProcess, ResetPin};
30use crate::transport::ti50emulator::gpio::Ti50GpioPin;
31use crate::transport::ti50emulator::i2c::Ti50I2cBus;
32use crate::transport::ti50emulator::uart::Ti50Uart;
33
34pub struct Ti50Emulator {
35 gpio_map: HashMap<String, Rc<dyn GpioPin>>,
37 i2c_map: HashMap<String, Rc<dyn Bus>>,
39 uart_map: HashMap<String, Rc<dyn Uart>>,
41 emu: Rc<EmulatorImpl>,
43}
44
45impl Ti50Emulator {
46 pub fn open(
48 executable_directory: &Path,
49 executable: &str,
50 instance_prefix: &str,
51 ) -> anyhow::Result<Self> {
52 let tstamp = SystemTime::now().duration_since(UNIX_EPOCH)?;
53 let instance_name = format!(
54 "{}_{}_{}_{}",
55 instance_prefix,
56 process::id(),
57 tstamp.as_secs(),
58 tstamp.as_nanos()
59 );
60
61 let mut instance_directory = PathBuf::from("/tmp");
62 instance_directory.push(&instance_name);
63
64 log::info!("Initializing Ti50Emulator instance: {}", instance_name);
65 fs::create_dir(&instance_directory).context("Falied to create instance directory")?;
66
67 let process = EmulatorProcess::init(&instance_directory, executable_directory, executable)?;
68
69 let conf = process.get_configurations()?;
70
71 let inner = Rc::new(Inner {
72 instance_directory,
73 process: RefCell::new(process),
74 gpio_map: RefCell::default(),
75 uarts: RefCell::default(),
76 });
77
78 let mut gpio_map: HashMap<String, Rc<dyn GpioPin>> = HashMap::new();
79 let mut i2c_map = HashMap::new();
80 let mut uart_map = HashMap::new();
81
82 let reset_pin = ResetPin::open(&inner)?;
83 gpio_map.insert("RESET".to_string(), Rc::new(reset_pin));
84 for (name, state) in conf.gpio.iter() {
85 inner
86 .gpio_map
87 .borrow_mut()
88 .insert(name.to_string(), gpio::GpioConfiguration::default());
89 let gpio: Rc<dyn GpioPin> = Rc::new(Ti50GpioPin::open(&inner, name, *state)?);
90 gpio_map.insert(name.to_uppercase(), Rc::clone(&gpio));
91 }
92 for (name, path) in conf.uart.iter() {
93 let uart: Rc<Ti50Uart> = Rc::new(Ti50Uart::open(&inner, path)?);
94 uart_map.insert(name.to_uppercase(), Rc::clone(&uart) as Rc<dyn Uart>);
95 inner.uarts.borrow_mut().push(Rc::downgrade(&uart));
96 }
97 for (name, path) in conf.i2c.iter() {
98 let i2c: Rc<dyn Bus> = Rc::new(Ti50I2cBus::open(&inner, path)?);
99 i2c_map.insert(name.to_uppercase(), Rc::clone(&i2c));
100 }
101 let ti50_emu = Ti50Emulator {
102 gpio_map,
103 i2c_map,
104 uart_map,
105 emu: Rc::new(EmulatorImpl::open(&inner)?),
106 };
107 Ok(ti50_emu)
108 }
109}
110
111impl Drop for Inner {
112 fn drop(&mut self) {
113 log::info!(
114 "Clenup Ti50Emulator instance directory: {}",
115 self.instance_directory.display()
116 );
117 if let Err(e) = fs::remove_dir_all(&self.instance_directory) {
118 log::error!("Can't remove instance directory error: {}", e)
119 }
120 }
121}
122
123pub struct Inner {
125 instance_directory: PathBuf,
127 process: RefCell<EmulatorProcess>,
129 gpio_map: RefCell<HashMap<String, gpio::GpioConfiguration>>,
131 uarts: RefCell<Vec<Weak<Ti50Uart>>>,
132}
133
134impl Inner {}
135
136impl Transport for Ti50Emulator {
138 fn capabilities(&self) -> Result<Capabilities> {
139 Ok(Capabilities::new(
140 Capability::UART | Capability::GPIO | Capability::I2C | Capability::EMULATOR,
141 ))
142 }
143
144 fn spi(&self, instance: &str) -> Result<Rc<dyn Target>> {
146 Err(TransportError::InvalidInstance(
147 TransportInterfaceType::Spi,
148 instance.to_string(),
149 ))?
150 }
151
152 fn i2c(&self, instance: &str) -> Result<Rc<dyn Bus>> {
154 Ok(Rc::clone(self.i2c_map.get(instance).ok_or_else(|| {
155 TransportError::InvalidInstance(TransportInterfaceType::I2c, instance.to_string())
156 })?))
157 }
158
159 fn uart(&self, instance: &str) -> Result<Rc<dyn Uart>> {
161 Ok(Rc::clone(self.uart_map.get(instance).ok_or_else(|| {
162 TransportError::InvalidInstance(TransportInterfaceType::Uart, instance.to_string())
163 })?))
164 }
165
166 fn gpio_pin(&self, pinname: &str) -> Result<Rc<dyn GpioPin>> {
168 Ok(Rc::clone(self.gpio_map.get(pinname).ok_or_else(|| {
169 TransportError::InvalidInstance(TransportInterfaceType::Gpio, pinname.to_string())
170 })?))
171 }
172
173 fn emulator(&self) -> Result<Rc<dyn Emulator>> {
175 Ok(self.emu.clone())
176 }
177}