1mod pwm_streamer;
2use std::time::Duration;
3
4pub use pwm_streamer::*;
5
6use readformat::{readf, readf1};
7pub use serialport;
8use serialport::{Error, SerialPort};
9
10#[derive(Clone, Copy, PartialEq, Eq)]
11pub enum PicoGPIOVersion {
12 V1_0,
13 Unknown,
14}
15
16#[derive(Clone, Copy, PartialEq, Eq)]
17pub enum PinValueRead {
18 Floating(Option<bool>),
19 Analog(u32),
20 Digital(bool),
21 PWM(u32),
22}
23#[derive(Clone, Copy, PartialEq, Eq)]
24pub enum PinValueWrite {
25 Floating,
26 Digital(bool),
27 PWM(u32),
28}
29
30impl PinValueRead {
31 pub fn matches(&self, written: &PinValueWrite) -> bool {
32 match (self, written) {
33 (PinValueRead::Floating(_), PinValueWrite::Floating) => true,
34 (PinValueRead::Digital(a), PinValueWrite::Digital(b)) if a == b => true,
35 (PinValueRead::PWM(a), PinValueWrite::PWM(b)) if a == b => true,
36 _ => false,
37 }
38 }
39
40 pub fn matches_in(&self, asked: &PinInput) -> bool {
41 matches!(
42 (self, asked),
43 (PinValueRead::Floating(_), PinInput::Floating)
44 | (PinValueRead::Analog(_), PinInput::Analog)
45 | (PinValueRead::Digital(_), PinInput::PDown)
46 | (PinValueRead::Digital(_), PinInput::PUp)
47 )
48 }
49}
50
51#[derive(Clone, Copy, PartialEq, Eq)]
65pub enum PinInput {
66 Analog,
67 Floating,
68 PDown,
69 PUp,
70}
71
72struct Params<PVType, const PINS: usize> {
73 pins: [PVType; PINS],
74 pwmfreq: u32,
75 pwmres: u8,
76 inares: u8,
77 streaming: bool,
78}
79
80pub struct PicoGPIO<Port: SerialPort, const PINS: usize = 256> {
81 port: Port,
82 version: PicoGPIOVersion,
83 intended: Params<PinValueWrite, PINS>,
85 actual: Params<PinValueRead, PINS>,
87 blocking: bool,
88}
89
90impl<Port: SerialPort, const PINS: usize> PicoGPIO<Port, PINS> {
91 pub fn new(mut serial_port: Port) -> Result<Self, Error> {
92 serial_port.set_timeout(Duration::from_millis(500))?;
93 serial_port.write_all("\r\n".as_bytes())?;
94 Ok(Self {
95 port: serial_port,
96 version: PicoGPIOVersion::Unknown,
97 intended: Params {
98 pins: [PinValueWrite::Floating; PINS],
99 pwmfreq: 0,
100 pwmres: 8,
101 inares: 10,
102 streaming: false,
103 },
104 actual: Params {
105 pins: [PinValueRead::Floating(None); PINS],
106 pwmfreq: 0,
107 pwmres: 8,
108 inares: 10,
109 streaming: false,
110 },
111 blocking: true,
112 })
113 }
114
115 pub fn poll(&mut self, mut min_lines: usize) -> Result<(), Error> {
116 loop {
117 if self.port.bytes_to_read()? == 0 && min_lines == 0 {
118 break;
119 }
120 let mut buf = [0u8; 1];
121 self.port.read_exact(&mut buf)?;
122 let mut line = vec![buf[0]];
123 loop {
124 let mut buf = [0u8; 1024];
125 let amt = self.port.read(&mut buf)?;
126 line.append(&mut buf[..amt].to_vec());
127 if *line.last().unwrap() as char == '\n' {
128 break;
129 }
130 }
131 for line in String::from_utf8(line).unwrap().split('\n') {
132 self.parse_line(line.trim())?;
133 min_lines = min_lines.saturating_sub(1);
134 }
135 }
136 Ok(())
137 }
138
139 fn parse_line(&mut self, line: &str) -> Result<(), Error> {
140 if line == "!OK" {
141 } else if let Some(v) = readf1("+PICO_GPIO {}", line) {
143 self.version = match v.as_str() {
144 "V1.0" => PicoGPIOVersion::V1_0,
145 _ => PicoGPIOVersion::Unknown,
146 };
147 } else if let Some(err) = readf1("!ERROR:{}", line) {
148 panic!("PicoGPIO version mismatch: ERROR {err}.");
149 } else if let Some(freq) = readf1("!PWMFREQ:{}", line) {
150 self.actual.pwmfreq = freq.parse().unwrap();
151 } else if let Some(res) = readf1("!PWMRES:{}", line) {
152 self.actual.pwmres = res.parse().unwrap();
153 } else if let Some(res) = readf1("!INARES:{}", line) {
154 self.actual.inares = res.parse().unwrap();
155 } else if line == "!STREAMING" {
156 self.actual.streaming = true;
157 } else if let Some([pin, val]) = readf("~{}={}", line).as_deref() {
158 self.actual.pins[pin.parse::<usize>().expect("invalid data from PicoGPIO!")] =
159 PinValueRead::Floating(Some(
160 val.parse::<u8>().expect("invalid data from PicoGPIO!") != 0,
161 ))
162 } else if let Some([pin, val]) = readf("/{}={}", line).as_deref() {
163 self.actual.pins[pin.parse::<usize>().expect("invalid data from PicoGPIO!")] =
164 PinValueRead::Analog(val.parse::<u32>().expect("invalid data from PicoGPIO!"))
165 } else if let Some([pin, val]) = readf("#{}={}", line).as_deref() {
166 self.actual.pins[pin.parse::<usize>().expect("invalid data from PicoGPIO!")] =
167 PinValueRead::PWM(val.parse::<u32>().expect("invalid data from PicoGPIO!"))
168 } else if let Some([pin, val]) = readf("{}={}", line).as_deref() {
169 self.actual.pins[pin.parse::<usize>().expect("invalid data from PicoGPIO!")] =
170 PinValueRead::Digital(val.parse::<u8>().expect("invalid data from PicoGPIO!") != 0)
171 }
172 Ok(())
173 }
174
175 pub fn set_manual(
176 &mut self,
177 pin: usize,
178 value: PinValueWrite,
179 block: bool,
180 ) -> Result<(), Error> {
181 self.intended.pins[pin] = value;
182 match value {
183 PinValueWrite::Floating => {
184 self.port.write_all(format!("float {pin}\r\n").as_bytes())?
185 }
186 PinValueWrite::Digital(val) => self
187 .port
188 .write_all(format!("out {pin}={}\r\n", if val { 1 } else { 0 }).as_bytes())?,
189 PinValueWrite::PWM(val) => self
190 .port
191 .write_all(format!("pwm {pin}={val}\r\n").as_bytes())?,
192 }
193 self.poll(0)?;
194 if block {
195 while !self.actual.pins[pin].matches(&value) {
196 self.poll(1)?;
197 }
198 }
199 Ok(())
200 }
201
202 pub fn get_manual(
203 &mut self,
204 pin: usize,
205 kind: PinInput,
206 cached: bool,
207 block: bool,
208 ) -> Result<PinValueRead, Error> {
209 if !cached {
210 self.intended.pins[pin] = PinValueWrite::Floating;
211 self.poll(0)?;
212 match kind {
213 PinInput::Floating => self.port.write_all(format!("float {pin}\r\n").as_bytes())?,
214 PinInput::Analog => self.port.write_all(format!("ina {pin}\r\n").as_bytes())?,
215 PinInput::PDown => self.port.write_all(format!("in {pin}\r\n").as_bytes())?,
216 PinInput::PUp => self.port.write_all(format!("in^ {pin}\r\n").as_bytes())?,
217 }
218 if block {
219 self.poll(1)?;
220 }
221 while !self.actual.pins[pin].matches_in(&kind) {
222 self.poll(1)?;
223 }
224 }
225
226 Ok(self.actual.pins[pin])
227 }
228
229 pub fn float(&mut self, pin: usize) -> Result<(), Error> {
230 self.set_manual(pin, PinValueWrite::Floating, self.blocking)
231 }
232
233 pub fn out_d(&mut self, pin: usize, val: bool) -> Result<(), Error> {
234 self.set_manual(pin, PinValueWrite::Digital(val), self.blocking)
235 }
236
237 pub fn out_pwm(&mut self, pin: usize, val: u32) -> Result<(), Error> {
238 self.set_manual(pin, PinValueWrite::PWM(val), self.blocking)
239 }
240
241 pub fn in_float(&mut self, pin: usize) -> Result<bool, Error> {
242 self.get_manual(pin, PinInput::Floating, false, self.blocking)
243 .map(|x| match x {
244 PinValueRead::Floating(Some(x)) => x,
245 _ => unreachable!(),
246 })
247 }
248
249 pub fn in_pulldn(&mut self, pin: usize) -> Result<bool, Error> {
250 self.get_manual(pin, PinInput::PDown, false, self.blocking)
251 .map(|x| match x {
252 PinValueRead::Digital(x) => x,
253 _ => unreachable!(),
254 })
255 }
256
257 pub fn in_pullup(&mut self, pin: usize) -> Result<bool, Error> {
258 self.get_manual(pin, PinInput::PUp, false, self.blocking)
259 .map(|x| match x {
260 PinValueRead::Digital(x) => x,
261 _ => unreachable!(),
262 })
263 }
264
265 pub fn in_analog(&mut self, pin: usize) -> Result<u32, Error> {
266 self.get_manual(pin, PinInput::Analog, false, self.blocking)
267 .map(|x| match x {
268 PinValueRead::Analog(x) => x,
269 _ => unreachable!(),
270 })
271 }
272
273 pub fn init_pwm(&mut self, freq: u32, res: u8, block: bool) -> Result<(), Error> {
274 self.intended.pwmres = res;
275 self.intended.pwmfreq = freq;
276 self.port
277 .write_all(format!("pwmres {res}\r\npwmfreq {freq}\r\n").as_bytes())?;
278 self.poll(0)?;
279 if block {
280 while self.actual.pwmfreq != freq || self.actual.pwmres != res {
281 self.poll(1)?;
282 }
283 }
284 Ok(())
285 }
286
287 pub fn pwmstream(mut self, pin: usize) -> Result<PwmStreamer<Port, PINS>, (Self, Error)> {
288 if let Err(e) = self
289 .init_pwm(self.intended.pwmfreq, 8, true)
290 .and_then(|()| {
291 self.port
292 .write_all(format!("pwmstream {pin}").as_bytes())
293 .map_err(|x| x.into())
294 })
295 {
296 return Err((self, e));
297 }
298 Ok(PwmStreamer::new(self, PwmStreamMode::PWM))
299 }
300
301 pub fn audiostream(mut self, pin: usize) -> Result<PwmStreamer<Port, PINS>, (Self, Error)> {
302 if let Err(e) = self
303 .init_pwm(self.intended.pwmfreq, 8, true)
304 .and_then(|()| {
305 self.port
306 .write_all(format!("audiostream {pin}").as_bytes())
307 .map_err(|x| x.into())
308 })
309 {
310 return Err((self, e));
311 }
312 Ok(PwmStreamer::new(self, PwmStreamMode::Audio))
313 }
314}