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::load_bitstream::LoadBitstream;
18use crate::app::TransportWrapper;
19use crate::backend;
20use crate::io::jtag::JtagParams;
21#[derive(Debug, Args)]
24pub struct InitializeTest {
25 #[arg(long, value_parser = PathBuf::from_str, default_value = "config")]
27 pub rcfile: PathBuf,
28
29 #[arg(long, default_value = "off")]
30 pub logging: LevelFilter,
31
32 #[command(flatten)]
33 pub backend_opts: backend::BackendOpts,
34
35 #[command(flatten)]
40 pub load_bitstream: LoadBitstream,
41
42 #[command(flatten)]
43 pub bootstrap: Bootstrap,
44
45 #[command(flatten)]
46 pub jtag_params: JtagParams,
47}
48
49impl InitializeTest {
50 pub fn init_logging(&self) {
51 let level = self.logging;
52 if level != LevelFilter::Off {
55 env_logger::Builder::from_default_env()
56 .format_target(true)
57 .format_module_path(false)
58 .format_timestamp_millis()
59 .filter(None, level)
60 .init();
61 }
62 }
63
64 pub fn parse_command_line(&self, mut args: ArgsOs) -> Result<Vec<OsString>> {
67 self.init_logging();
69 if self.rcfile.as_os_str().is_empty() {
70 return Ok(Vec::new());
72 }
73
74 let rcfile = if let Some(base) = ProjectDirs::from("org", "opentitan", "opentitantool") {
77 base.config_dir().join(&self.rcfile)
78 } else {
79 self.rcfile.clone()
80 };
81
82 let mut arguments = vec![args.next().unwrap()];
84
85 match std::fs::read_to_string(&rcfile) {
87 Ok(content) => {
88 for line in content.split('\n') {
89 let (line, _) = line.split_once('#').unwrap_or((line, ""));
91 arguments.extend(shellwords::split(line)?.iter().map(OsString::from));
92 }
93 Ok(())
94 }
95 Err(e) if e.kind() == ErrorKind::NotFound => {
96 log::warn!("Could not read {:?}. Ignoring.", rcfile);
97 Ok(())
98 }
99 Err(e) => Err(anyhow::Error::new(e).context(format!("Reading file {:?}", rcfile))),
100 }?;
101
102 arguments.extend(args);
104 Ok(arguments)
105 }
106
107 pub fn print_result(
110 operation: &str,
111 result: Result<Option<Box<dyn erased_serde::Serialize>>>,
112 ) -> Result<()> {
113 match result {
114 Ok(Some(value)) => {
115 log::info!("{}: success.", operation);
116 println!(
117 "\"{}\": {}",
118 operation,
119 serde_json::to_string_pretty(&value)?
120 );
121 Ok(())
122 }
123 Ok(None) => {
124 log::info!("{}: success.", operation);
125 println!("\"{}\": true", operation);
126 Ok(())
127 }
128 Err(e) => {
129 log::info!("{}: {:?}.", operation, e);
130 println!("\"{}\": false", operation);
131 Err(e)
132 }
133 }
134 }
135
136 pub fn init_target(&self) -> Result<TransportWrapper> {
137 let transport = backend::create(&self.backend_opts)?;
139
140 transport.apply_default_configuration(None)?;
142
143 let _uart = self.bootstrap.options.uart_params.create(&transport)?;
145
146 Self::print_result("load_bitstream", self.load_bitstream.init(&transport))?;
148
149 Self::print_result("bootstrap", self.bootstrap.init(&transport))?;
151 Ok(transport)
152 }
153}