opentitanlib/test_utils/
init.rs1use anyhow::Result;
6use clap::Args;
7use directories::ProjectDirs;
8use log::LevelFilter;
9use std::env::ArgsOs;
10use std::ffi::OsString;
11use std::io::ErrorKind;
12use std::iter::Iterator;
13use std::path::PathBuf;
14use std::str::FromStr;
15
16use super::bootstrap::Bootstrap;
17use super::fpga_backdoor::LoadMemories;
18use super::load_bitstream::LoadBitstream;
19use crate::app::TransportWrapper;
20use crate::backend;
21use crate::io::jtag::JtagParams;
22#[derive(Debug, Args)]
25pub struct InitializeTest {
26 #[arg(long, value_parser = PathBuf::from_str, default_value = "config")]
28 pub rcfile: PathBuf,
29
30 #[arg(long, default_value = "off")]
31 pub logging: LevelFilter,
32
33 #[arg(short, long)]
35 drop_reset: bool,
36
37 #[command(flatten)]
38 pub backend_opts: backend::BackendOpts,
39
40 #[command(flatten)]
45 pub load_bitstream: LoadBitstream,
46
47 #[command(flatten)]
48 pub load_memories: LoadMemories,
49
50 #[command(flatten)]
51 pub bootstrap: Bootstrap,
52
53 #[command(flatten)]
54 pub jtag_params: JtagParams,
55}
56
57impl InitializeTest {
58 pub fn init_logging(&self) {
59 let level = self.logging;
60 if level != LevelFilter::Off {
63 env_logger::Builder::from_default_env()
64 .format_target(true)
65 .format_module_path(false)
66 .format_timestamp_millis()
67 .filter(None, level)
68 .init();
69 }
70 }
71
72 pub fn parse_command_line(&self, mut args: ArgsOs) -> Result<Vec<OsString>> {
75 self.init_logging();
77 if self.rcfile.as_os_str().is_empty() {
78 return Ok(Vec::new());
80 }
81
82 let rcfile = if let Some(base) = ProjectDirs::from("org", "opentitan", "opentitantool") {
85 base.config_dir().join(&self.rcfile)
86 } else {
87 self.rcfile.clone()
88 };
89
90 let mut arguments = vec![args.next().unwrap()];
92
93 match std::fs::read_to_string(&rcfile) {
95 Ok(content) => {
96 for line in content.split('\n') {
97 let (line, _) = line.split_once('#').unwrap_or((line, ""));
99 arguments.extend(shellwords::split(line)?.iter().map(OsString::from));
100 }
101 Ok(())
102 }
103 Err(e) if e.kind() == ErrorKind::NotFound => {
104 log::warn!("Could not read {:?}. Ignoring.", rcfile);
105 Ok(())
106 }
107 Err(e) => Err(anyhow::Error::new(e).context(format!("Reading file {:?}", rcfile))),
108 }?;
109
110 arguments.extend(args);
112 Ok(arguments)
113 }
114
115 pub fn print_result(
118 operation: &str,
119 result: Result<Option<Box<dyn erased_serde::Serialize>>>,
120 ) -> Result<()> {
121 match result {
122 Ok(Some(value)) => {
123 log::info!("{}: success.", operation);
124 println!(
125 "\"{}\": {}",
126 operation,
127 serde_json::to_string_pretty(&value)?
128 );
129 Ok(())
130 }
131 Ok(None) => {
132 log::info!("{}: success.", operation);
133 println!("\"{}\": true", operation);
134 Ok(())
135 }
136 Err(e) => {
137 log::info!("{}: {:?}.", operation, e);
138 println!("\"{}\": false", operation);
139 Err(e)
140 }
141 }
142 }
143
144 pub fn init_target(&self) -> Result<TransportWrapper> {
145 let transport = backend::create(&self.backend_opts)?;
147
148 transport.apply_default_configuration(None)?;
150
151 if self.drop_reset {
152 transport.pin_strapping("RESET")?.remove()?;
153 }
154
155 let _uart = self.bootstrap.options.uart_params.create(&transport)?;
157
158 Self::print_result(
160 "load_bitstream",
161 self.load_bitstream.init(&transport).map(|_| None),
162 )?;
163
164 Self::print_result(
166 "load_memories",
167 self.load_memories
168 .init(&transport, &self.jtag_params)
169 .map(|_| None),
170 )?;
171
172 Self::print_result("bootstrap", self.bootstrap.init(&transport))?;
174 Ok(transport)
175 }
176}