opentitanlib/transport/proxy/
gpio.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use 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    // Convenience method for issuing GPIO commands via proxy protocol.
37    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    /// Reads the value of the GPIO pin `id`.
50    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    /// Sets the value of the GPIO pin `id` to `value`.
58    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    // Convenience method for issuing GPIO monitoring commands via proxy protocol.
128    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    // Convenience method for issuing GPIO bitbanging commands via proxy protocol.
189    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    // Convenience method for issuing GPIO dac-banging commands via proxy protocol.
200    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    // Convenience method for issuing GPIO bitbanging commands via proxy protocol.
314    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    // Convenience method for issuing GPIO dacbanging commands via proxy protocol.
362    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}