opentitanlib/test_utils/
gpio_monitor.rs1use anyhow::{Result, bail, ensure};
6use std::borrow::Borrow;
7use std::rc::Rc;
8
9use crate::app::TransportWrapper;
10use crate::io::gpio::{ClockNature, GpioMonitoring, MonitoringEvent};
11use crate::util::vcd::{dump_vcd, vcd_from_edges};
12
13pub struct GpioMon<'a> {
17 transport: &'a TransportWrapper,
19 monitor: Rc<dyn GpioMonitoring>,
21 pins: Vec<String>,
23 dump_on_drop: bool,
25 still_monitoring: bool,
27 waves: Waves,
29}
30
31pub struct Waves {
32 pin_names: Vec<String>,
34 initial_levels: Vec<bool>,
36 initial_timestamp: u64,
38 final_timestamp: u64,
40 resolution: u64,
42 events: Vec<MonitoringEvent>,
44}
45
46impl<'a> GpioMon<'a> {
47 pub fn start(
51 transport: &'a TransportWrapper,
52 pins: &[(&str, &str)],
53 dump_on_drop: bool,
54 ) -> Result<Self> {
55 let pin_names = pins
56 .iter()
57 .map(|(name, hname)| {
58 if hname.is_empty() {
59 name.to_string()
60 } else {
61 hname.to_string()
62 }
63 })
64 .collect::<Vec<_>>();
65
66 let monitor = transport.gpio_monitoring()?;
67 let clock_nature = monitor.get_clock_nature()?;
68 let ClockNature::Wallclock { resolution, .. } = clock_nature else {
69 bail!("the transport GPIO monitor does not have reliable clock source");
70 };
71 let pins = pins
72 .iter()
73 .map(|(name, _)| name.to_string())
74 .collect::<Vec<_>>();
75 let gpio_pins = transport.gpio_pins(&pins)?;
76 let gpios_pins = &gpio_pins.iter().map(Rc::borrow).collect::<Vec<_>>();
77 let start = monitor.monitoring_start(gpios_pins)?;
78
79 Ok(GpioMon {
80 transport,
81 monitor,
82 pins,
83 dump_on_drop,
84 still_monitoring: true,
85 waves: Waves::new(pin_names, start.initial_levels, start.timestamp, resolution),
86 })
87 }
88
89 pub fn timestamp_to_ns(&self, timestamp: u64) -> u64 {
90 self.waves.timestamp_to_ns(timestamp)
91 }
92
93 pub fn signal_index(&self, name: &str) -> Option<usize> {
94 self.waves.signal_index(name)
95 }
96
97 pub fn initial_levels(&self) -> Vec<bool> {
98 self.waves.initial_levels()
99 }
100
101 pub fn all_events(&self) -> impl Iterator<Item = &MonitoringEvent> {
102 self.waves.all_events()
103 }
104
105 pub fn read(&mut self, continue_monitoring: bool) -> Result<Vec<MonitoringEvent>> {
106 ensure!(
107 self.still_monitoring,
108 "cannot call read() on GpioMon after monitoring has stopped"
109 );
110 let gpio_pins = self.transport.gpio_pins(&self.pins)?;
111 let gpios_pins = &gpio_pins.iter().map(Rc::borrow).collect::<Vec<_>>();
112 let resp = self
113 .monitor
114 .monitoring_read(gpios_pins, continue_monitoring)?;
115 self.still_monitoring = continue_monitoring;
116 self.waves.add_events(&resp.events);
117 self.waves.final_timestamp = resp.timestamp;
118 Ok(resp.events)
119 }
120
121 pub fn dump_on_drop(&mut self, dump_on_drop: bool) {
122 self.dump_on_drop = dump_on_drop
123 }
124
125 pub fn dump_vcd(&self) -> Result<String> {
126 self.waves.dump_vcd()
127 }
128}
129
130impl TryFrom<GpioMon<'_>> for Waves {
134 type Error = anyhow::Error;
135
136 fn try_from(mut gpio_mon: GpioMon<'_>) -> Result<Waves> {
137 if gpio_mon.still_monitoring {
138 let _ = gpio_mon.read(false)?;
139 }
140 gpio_mon.dump_on_drop = false;
141 let waves = std::mem::replace(
142 &mut gpio_mon.waves,
143 Waves::new(Vec::new(), Vec::new(), 0, 1),
144 );
145 Ok(waves)
146 }
147}
148
149impl Waves {
150 pub fn new(
151 pin_names: Vec<String>,
152 initial_levels: Vec<bool>,
153 initial_timestamp: u64,
154 resolution: u64,
155 ) -> Waves {
156 Waves {
157 pin_names,
158 initial_levels,
159 initial_timestamp,
160 final_timestamp: initial_timestamp,
161 resolution,
162 events: vec![],
163 }
164 }
165
166 pub fn add_signal(&mut self, name: String, initial_level: bool) -> usize {
168 self.pin_names.push(name);
169 self.initial_levels.push(initial_level);
170 self.pin_names.len() - 1
171 }
172
173 pub fn add_event(&mut self, event: MonitoringEvent) {
174 self.events.push(event)
175 }
176
177 pub fn add_events(&mut self, event: &[MonitoringEvent]) {
178 self.events.extend_from_slice(event)
179 }
180
181 pub fn signal_index(&self, name: &str) -> Option<usize> {
182 self.pin_names.iter().position(|x| x == name)
183 }
184
185 pub fn initial_levels(&self) -> Vec<bool> {
186 self.initial_levels.clone()
187 }
188
189 pub fn set_final_timestamp(&mut self, ts: u64) {
190 self.final_timestamp = ts;
191 }
192
193 pub fn timestamp_to_ns(&self, timestamp: u64) -> u64 {
194 (timestamp - self.initial_timestamp) * 1000000000u64 / self.resolution
195 }
196
197 pub fn ns_to_timestamp(&self, ns: u64) -> u64 {
198 self.initial_timestamp + self.resolution * ns / 1000000000u64
199 }
200
201 pub fn all_events(&self) -> impl Iterator<Item = &MonitoringEvent> {
202 self.events.iter()
203 }
204
205 pub fn sort_events(&mut self) {
206 self.events.sort_by(|a, b| a.timestamp.cmp(&b.timestamp));
207 }
208
209 pub fn dump_vcd(&self) -> Result<String> {
211 let pin_names = self
212 .pin_names
213 .iter()
214 .map(|n| Some(n.to_string()))
215 .collect::<Vec<_>>();
216 dump_vcd(&vcd_from_edges(
217 pin_names,
218 self.resolution,
219 self.initial_timestamp,
220 &self.initial_levels,
221 &self.events,
222 self.final_timestamp,
223 )?)
224 }
225}
226
227impl Drop for GpioMon<'_> {
228 fn drop(&mut self) {
229 let error = if self.still_monitoring {
231 self.read(false).is_err()
232 } else {
233 false
234 };
235 if self.dump_on_drop {
236 if error {
237 log::error!(
238 "an error occured when reading the monitoring events, some events have been lost"
239 );
240 }
241 log::info!(
242 "====[ VCD dump ]====\n{}\n====[ end dump ]====",
243 self.dump_vcd().unwrap()
244 );
245 }
246 }
247}