opentitanlib/transport/proxy/
gpio.rs1use anyhow::{Result, bail, ensure};
6use std::rc::Rc;
7use std::time::Duration;
8
9use super::ProxyError;
10use crate::io::gpio::{
11 BitbangEntry, ClockNature, DacBangEntry, GpioBitbangOperation, GpioBitbanging,
12 GpioDacBangOperation, GpioError, GpioMonitoring, GpioPin, MonitoringReadResponse,
13 MonitoringStartResponse, PinMode, PullMode,
14};
15use crate::proxy::protocol::{
16 BitbangEntryRequest, BitbangEntryResponse, DacBangEntryRequest, GpioBitRequest,
17 GpioBitResponse, GpioDacRequest, GpioDacResponse, GpioMonRequest, GpioMonResponse, GpioRequest,
18 GpioResponse, Request, Response,
19};
20use crate::transport::proxy::{Inner, Proxy};
21
22pub struct ProxyGpioPin {
23 inner: Rc<Inner>,
24 pinname: String,
25}
26
27impl ProxyGpioPin {
28 pub fn open(proxy: &Proxy, pinname: &str) -> Result<Self> {
29 let result = Self {
30 inner: Rc::clone(&proxy.inner),
31 pinname: pinname.to_string(),
32 };
33 Ok(result)
34 }
35
36 fn execute_command(&self, command: GpioRequest) -> Result<GpioResponse> {
38 match self.inner.execute_command(Request::Gpio {
39 id: self.pinname.clone(),
40 command,
41 })? {
42 Response::Gpio(resp) => Ok(resp),
43 _ => bail!(ProxyError::UnexpectedReply()),
44 }
45 }
46}
47
48impl GpioPin for ProxyGpioPin {
49 fn read(&self) -> Result<bool> {
51 match self.execute_command(GpioRequest::Read)? {
52 GpioResponse::Read { value } => Ok(value),
53 _ => bail!(ProxyError::UnexpectedReply()),
54 }
55 }
56
57 fn write(&self, value: bool) -> Result<()> {
59 match self.execute_command(GpioRequest::Write { logic: value })? {
60 GpioResponse::Write => Ok(()),
61 _ => bail!(ProxyError::UnexpectedReply()),
62 }
63 }
64
65 fn set_mode(&self, mode: PinMode) -> Result<()> {
66 match self.execute_command(GpioRequest::SetMode { mode })? {
67 GpioResponse::SetMode => Ok(()),
68 _ => bail!(ProxyError::UnexpectedReply()),
69 }
70 }
71
72 fn set_pull_mode(&self, pull: PullMode) -> Result<()> {
73 match self.execute_command(GpioRequest::SetPullMode { pull })? {
74 GpioResponse::SetPullMode => Ok(()),
75 _ => bail!(ProxyError::UnexpectedReply()),
76 }
77 }
78
79 fn analog_read(&self) -> Result<f32> {
80 match self.execute_command(GpioRequest::AnalogRead)? {
81 GpioResponse::AnalogRead { value } => Ok(value),
82 _ => bail!(ProxyError::UnexpectedReply()),
83 }
84 }
85
86 fn analog_write(&self, volts: f32) -> Result<()> {
87 match self.execute_command(GpioRequest::AnalogWrite { value: volts })? {
88 GpioResponse::AnalogWrite => Ok(()),
89 _ => bail!(ProxyError::UnexpectedReply()),
90 }
91 }
92
93 fn set(
94 &self,
95 mode: Option<PinMode>,
96 value: Option<bool>,
97 pull: Option<PullMode>,
98 analog_value: Option<f32>,
99 ) -> Result<()> {
100 match self.execute_command(GpioRequest::MultiSet {
101 mode,
102 value,
103 pull,
104 analog_value,
105 })? {
106 GpioResponse::MultiSet => Ok(()),
107 _ => bail!(ProxyError::UnexpectedReply()),
108 }
109 }
110
111 fn get_internal_pin_name(&self) -> Option<&str> {
112 Some(&self.pinname)
113 }
114}
115
116pub struct GpioMonitoringImpl {
117 inner: Rc<Inner>,
118}
119
120impl GpioMonitoringImpl {
121 pub fn new(proxy: &Proxy) -> Result<Self> {
122 Ok(Self {
123 inner: Rc::clone(&proxy.inner),
124 })
125 }
126
127 fn execute_command(&self, command: GpioMonRequest) -> Result<GpioMonResponse> {
129 match self
130 .inner
131 .execute_command(Request::GpioMonitoring { command })?
132 {
133 Response::GpioMonitoring(resp) => Ok(resp),
134 _ => bail!(ProxyError::UnexpectedReply()),
135 }
136 }
137}
138
139impl GpioMonitoring for GpioMonitoringImpl {
140 fn get_clock_nature(&self) -> Result<ClockNature> {
141 match self.execute_command(GpioMonRequest::GetClockNature)? {
142 GpioMonResponse::GetClockNature { resp } => Ok(resp),
143 _ => bail!(ProxyError::UnexpectedReply()),
144 }
145 }
146
147 fn monitoring_start(&self, pins: &[&dyn GpioPin]) -> Result<MonitoringStartResponse> {
148 let pins = pins
149 .iter()
150 .map(|p| p.get_internal_pin_name().unwrap().to_string())
151 .collect::<Vec<String>>();
152 match self.execute_command(GpioMonRequest::Start { pins })? {
153 GpioMonResponse::Start { resp } => Ok(resp),
154 _ => bail!(ProxyError::UnexpectedReply()),
155 }
156 }
157
158 fn monitoring_read(
159 &self,
160 pins: &[&dyn GpioPin],
161 continue_monitoring: bool,
162 ) -> Result<MonitoringReadResponse> {
163 let pins = pins
164 .iter()
165 .map(|p| p.get_internal_pin_name().unwrap().to_string())
166 .collect::<Vec<String>>();
167 match self.execute_command(GpioMonRequest::Read {
168 pins,
169 continue_monitoring,
170 })? {
171 GpioMonResponse::Read { resp } => Ok(resp),
172 _ => bail!(ProxyError::UnexpectedReply()),
173 }
174 }
175}
176
177pub struct GpioBitbangingImpl {
178 inner: Rc<Inner>,
179}
180
181impl GpioBitbangingImpl {
182 pub fn new(proxy: &Proxy) -> Result<Self> {
183 Ok(Self {
184 inner: Rc::clone(&proxy.inner),
185 })
186 }
187
188 fn execute_command(&self, command: GpioBitRequest) -> Result<GpioBitResponse> {
190 match self
191 .inner
192 .execute_command(Request::GpioBitbanging { command })?
193 {
194 Response::GpioBitbanging(resp) => Ok(resp),
195 _ => bail!(ProxyError::UnexpectedReply()),
196 }
197 }
198
199 fn execute_dac_command(&self, command: GpioDacRequest) -> Result<GpioDacResponse> {
201 match self
202 .inner
203 .execute_command(Request::GpioDacBanging { command })?
204 {
205 Response::GpioDacBanging(resp) => Ok(resp),
206 _ => bail!(ProxyError::UnexpectedReply()),
207 }
208 }
209}
210
211impl GpioBitbanging for GpioBitbangingImpl {
212 fn start<'a>(
213 &self,
214 pins: &[&dyn GpioPin],
215 clock_tick: Duration,
216 waveform: Box<[BitbangEntry<'a, 'a>]>,
217 ) -> Result<Box<dyn GpioBitbangOperation<'a, 'a> + 'a>> {
218 let pins = pins
219 .iter()
220 .map(|p| p.get_internal_pin_name().unwrap().to_string())
221 .collect::<Vec<String>>();
222
223 let mut req: Vec<BitbangEntryRequest> = Vec::new();
224 for entry in waveform.iter() {
225 match entry {
226 BitbangEntry::Write(wbuf) => req.push(BitbangEntryRequest::Write {
227 data: wbuf.to_vec(),
228 }),
229 BitbangEntry::Both(wbuf, rbuf) => {
230 ensure!(
231 rbuf.len() == wbuf.len(),
232 GpioError::MismatchedDataLength(wbuf.len(), rbuf.len())
233 );
234 req.push(BitbangEntryRequest::Both {
235 data: wbuf.to_vec(),
236 })
237 }
238 BitbangEntry::WriteOwned(buf) => {
239 req.push(BitbangEntryRequest::Write { data: buf.to_vec() })
240 }
241 BitbangEntry::BothOwned(buf) => {
242 req.push(BitbangEntryRequest::Both { data: buf.to_vec() })
243 }
244 BitbangEntry::Delay(ticks) => req.push(BitbangEntryRequest::Delay {
245 clock_ticks: *ticks,
246 }),
247 BitbangEntry::Await { mask, pattern } => req.push(BitbangEntryRequest::Await {
248 mask: *mask,
249 pattern: *pattern,
250 }),
251 }
252 }
253 match self.execute_command(GpioBitRequest::Start {
254 pins,
255 clock_ns: clock_tick.as_nanos() as u64,
256 entries: req,
257 })? {
258 GpioBitResponse::Start => Ok(Box::new(GpioBitbangOperationImpl {
259 inner: Rc::clone(&self.inner),
260 waveform,
261 })),
262 _ => bail!(ProxyError::UnexpectedReply()),
263 }
264 }
265
266 fn dac_start(
267 &self,
268 pins: &[&dyn GpioPin],
269 clock_tick: Duration,
270 waveform: Box<[DacBangEntry]>,
271 ) -> Result<Box<dyn GpioDacBangOperation>> {
272 let pins = pins
273 .iter()
274 .map(|p| p.get_internal_pin_name().unwrap().to_string())
275 .collect::<Vec<String>>();
276
277 let mut req: Vec<DacBangEntryRequest> = Vec::new();
278 for entry in waveform.iter() {
279 match entry {
280 DacBangEntry::Write(wbuf) => req.push(DacBangEntryRequest::Write {
281 data: wbuf.to_vec(),
282 }),
283 DacBangEntry::WriteOwned(wbuf) => req.push(DacBangEntryRequest::Write {
284 data: wbuf.to_vec(),
285 }),
286 DacBangEntry::Delay(ticks) => req.push(DacBangEntryRequest::Delay {
287 clock_ticks: *ticks,
288 }),
289 DacBangEntry::Linear(ticks) => req.push(DacBangEntryRequest::Linear {
290 clock_ticks: *ticks,
291 }),
292 }
293 }
294 match self.execute_dac_command(GpioDacRequest::Start {
295 pins,
296 clock_ns: clock_tick.as_nanos() as u64,
297 entries: req,
298 })? {
299 GpioDacResponse::Start => Ok(Box::new(GpioDacBangOperationImpl {
300 inner: Rc::clone(&self.inner),
301 })),
302 _ => bail!(ProxyError::UnexpectedReply()),
303 }
304 }
305}
306
307pub struct GpioBitbangOperationImpl<'a> {
308 inner: Rc<Inner>,
309 waveform: Box<[BitbangEntry<'a, 'a>]>,
310}
311
312impl<'a> GpioBitbangOperationImpl<'a> {
313 fn execute_command(&self, command: GpioBitRequest) -> Result<GpioBitResponse> {
315 match self
316 .inner
317 .execute_command(Request::GpioBitbanging { command })?
318 {
319 Response::GpioBitbanging(resp) => Ok(resp),
320 _ => bail!(ProxyError::UnexpectedReply()),
321 }
322 }
323}
324
325impl<'a> GpioBitbangOperation<'a, 'a> for GpioBitbangOperationImpl<'a> {
326 fn query(&mut self) -> Result<bool> {
327 match self.execute_command(GpioBitRequest::Query)? {
328 GpioBitResponse::QueryNotDone => Ok(false),
329 GpioBitResponse::QueryDone { entries: resp } => {
330 ensure!(
331 resp.len() == self.waveform.len(),
332 ProxyError::UnexpectedReply()
333 );
334 for pair in resp.iter().zip(self.waveform.iter_mut()) {
335 match pair {
336 (BitbangEntryResponse::Both { data }, BitbangEntry::Both(_, rbuf)) => {
337 rbuf.clone_from_slice(data);
338 }
339 (BitbangEntryResponse::Write, BitbangEntry::Write(_)) => (),
340 (BitbangEntryResponse::Delay, BitbangEntry::Delay(_)) => (),
341 (BitbangEntryResponse::Await, BitbangEntry::Await { .. }) => (),
342 _ => bail!(ProxyError::UnexpectedReply()),
343 }
344 }
345 Ok(true)
346 }
347 _ => bail!(ProxyError::UnexpectedReply()),
348 }
349 }
350
351 fn get_result(self: Box<Self>) -> Result<Box<[BitbangEntry<'a, 'a>]>> {
352 Ok(self.waveform)
353 }
354}
355
356pub struct GpioDacBangOperationImpl {
357 inner: Rc<Inner>,
358}
359
360impl GpioDacBangOperationImpl {
361 fn execute_command(&self, command: GpioDacRequest) -> Result<GpioDacResponse> {
363 match self
364 .inner
365 .execute_command(Request::GpioDacBanging { command })?
366 {
367 Response::GpioDacBanging(resp) => Ok(resp),
368 _ => bail!(ProxyError::UnexpectedReply()),
369 }
370 }
371}
372
373impl GpioDacBangOperation for GpioDacBangOperationImpl {
374 fn query(&mut self) -> Result<bool> {
375 match self.execute_command(GpioDacRequest::Query)? {
376 GpioDacResponse::QueryNotDone => Ok(false),
377 GpioDacResponse::QueryDone => Ok(true),
378 _ => bail!(ProxyError::UnexpectedReply()),
379 }
380 }
381}