1use crate::{
11 gpio::{
12 self,
13 AlternateFunction,
14 AnyPin,
15 Flex,
16 InputPin,
17 InputSignalType,
18 Level,
19 NoPin,
20 OutputPin,
21 OutputSignalType,
22 Pin,
23 PinGuard,
24 Pull,
25 FUNC_IN_SEL_OFFSET,
26 GPIO_FUNCTION,
27 INPUT_SIGNAL_MAX,
28 OUTPUT_SIGNAL_MAX,
29 },
30 peripheral::Peripheral,
31 peripherals::GPIO,
32 private::{self, Sealed},
33};
34
35#[allow(
40 private_bounds,
41 reason = "InputConnection is unstable, but the trait needs to be public"
42)]
43pub trait PeripheralInput: Into<InputConnection> + 'static + crate::private::Sealed {}
44
45#[allow(
50 private_bounds,
51 reason = "OutputConnection is unstable, but the trait needs to be public"
52)]
53pub trait PeripheralOutput: Into<OutputConnection> + 'static + crate::private::Sealed {}
54
55impl<P: InputPin> PeripheralInput for P {}
57impl<P: OutputPin> PeripheralOutput for P {}
58
59impl PeripheralInput for Flex<'static> {}
61impl PeripheralOutput for Flex<'static> {}
62
63impl PeripheralInput for NoPin {}
65impl PeripheralOutput for NoPin {}
66
67impl PeripheralInput for Level {}
68impl PeripheralOutput for Level {}
69
70impl PeripheralInput for InputSignal {}
72impl PeripheralInput for OutputSignal {}
73impl PeripheralOutput for OutputSignal {}
74
75impl PeripheralInput for InputConnection {}
77impl PeripheralInput for OutputConnection {}
78impl PeripheralOutput for OutputConnection {}
79
80impl gpio::InputSignal {
81 fn can_use_gpio_matrix(self) -> bool {
82 self as InputSignalType <= INPUT_SIGNAL_MAX
83 }
84
85 #[inline]
94 pub fn connect_to(self, pin: impl Peripheral<P = impl PeripheralInput>) {
95 crate::into_mapped_ref!(pin);
96
97 pin.connect_input_to_peripheral(self);
98 }
99}
100
101impl gpio::OutputSignal {
102 fn can_use_gpio_matrix(self) -> bool {
103 self as OutputSignalType <= OUTPUT_SIGNAL_MAX
104 }
105
106 #[inline]
114 pub fn connect_to(self, pin: impl Peripheral<P = impl PeripheralOutput>) {
115 crate::into_mapped_ref!(pin);
116
117 pin.connect_peripheral_to_output(self);
118 }
119
120 #[inline]
122 pub fn disconnect_from(self, pin: impl Peripheral<P = impl PeripheralOutput>) {
123 crate::into_mapped_ref!(pin);
124
125 pin.disconnect_from_peripheral_output(self);
126 }
127}
128
129pub(crate) fn connect_input_signal(
138 signal: gpio::InputSignal,
139 input: u8,
140 invert: bool,
141 use_gpio_matrix: bool,
142) {
143 assert!(
144 signal.can_use_gpio_matrix() || !use_gpio_matrix,
145 "{:?} cannot be routed through the GPIO matrix",
146 signal
147 );
148 GPIO::regs()
149 .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET)
150 .write(|w| unsafe {
151 w.sel().bit(use_gpio_matrix);
152 w.in_inv_sel().bit(invert);
153 w.in_sel().bits(input) });
155}
156
157fn connect_pin_to_input_signal(
158 pin: &AnyPin,
159 signal: gpio::InputSignal,
160 is_inverted: bool,
161 force_gpio: bool,
162) {
163 let af = if is_inverted || force_gpio {
164 GPIO_FUNCTION
165 } else {
166 pin.input_signals(private::Internal)
167 .iter()
168 .find(|(_af, s)| *s == signal)
169 .map(|(af, _)| *af)
170 .unwrap_or(GPIO_FUNCTION)
171 };
172
173 pin.set_alternate_function(af);
174
175 connect_input_signal(signal, pin.number(), is_inverted, af == GPIO_FUNCTION);
176}
177
178fn connect_peripheral_to_output(
179 pin: &AnyPin,
180 signal: gpio::OutputSignal,
181 is_inverted: bool,
182 force_gpio: bool,
183 peripheral_control_output_enable: bool,
184 invert_output_enable: bool,
185) {
186 let af = if is_inverted || force_gpio {
187 GPIO_FUNCTION
188 } else {
189 pin.output_signals(private::Internal)
190 .iter()
191 .find(|(_af, s)| *s == signal)
192 .map(|(af, _)| *af)
193 .unwrap_or(GPIO_FUNCTION)
194 };
195
196 assert!(
197 signal.can_use_gpio_matrix() || af != GPIO_FUNCTION,
198 "{:?} cannot be routed through the GPIO matrix",
199 signal
200 );
201
202 pin.set_alternate_function(af);
203
204 GPIO::regs()
207 .func_out_sel_cfg(pin.number() as usize)
208 .write(|w| unsafe {
209 if af == GPIO_FUNCTION {
210 w.out_sel().bits(signal as _);
213 w.inv_sel().bit(is_inverted);
214 }
215 w.oen_sel().bit(!peripheral_control_output_enable);
216 w.oen_inv_sel().bit(invert_output_enable)
217 });
218}
219
220fn disconnect_peripheral_output_from_pin(pin: &AnyPin, signal: gpio::OutputSignal) {
221 pin.set_alternate_function(GPIO_FUNCTION);
222
223 GPIO::regs()
224 .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET)
225 .write(|w| w.sel().clear_bit());
226}
227
228#[instability::unstable]
232pub struct InputSignal {
233 pin: AnyPin,
234 is_inverted: bool,
235}
236
237impl<P> From<P> for InputSignal
238where
239 P: InputPin,
240{
241 fn from(input: P) -> Self {
242 Self::new(input.degrade())
243 }
244}
245
246impl From<Flex<'static>> for InputSignal {
247 fn from(input: Flex<'static>) -> Self {
248 Self::new(unsafe { AnyPin::steal(input.pin.number()) })
249 }
250}
251
252impl Clone for InputSignal {
253 fn clone(&self) -> Self {
254 Self {
255 pin: unsafe { self.pin.clone_unchecked() },
256 is_inverted: self.is_inverted,
257 }
258 }
259}
260
261impl Peripheral for InputSignal {
262 type P = Self;
263
264 unsafe fn clone_unchecked(&self) -> Self::P {
265 self.clone()
266 }
267}
268
269impl Sealed for InputSignal {}
270
271impl InputSignal {
272 pub(crate) fn new(pin: AnyPin) -> Self {
273 Self {
274 pin,
275 is_inverted: false,
276 }
277 }
278
279 pub fn number(&self) -> u8 {
281 self.pin.number()
282 }
283
284 pub fn level(&self) -> Level {
286 self.is_input_high().into()
287 }
288
289 pub fn invert(&mut self) {
293 self.is_inverted = !self.is_inverted;
294 }
295
296 pub fn inverted(mut self) -> Self {
301 self.invert();
302 self
303 }
304
305 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
311 connect_pin_to_input_signal(&self.pin, signal, self.is_inverted, true);
312 }
313
314 delegate::delegate! {
315 #[doc(hidden)]
316 to self.pin {
317 pub fn pull_direction(&self, pull: Pull);
318 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
319 pub fn init_input(&self, pull: Pull);
320 pub fn is_input_high(&self) -> bool;
321 pub fn enable_input(&self, on: bool);
322 }
323 }
324}
325
326struct DirectInputSignal {
330 pin: AnyPin,
331}
332
333impl Clone for DirectInputSignal {
334 fn clone(&self) -> Self {
335 Self::new(unsafe { self.pin.clone_unchecked() })
336 }
337}
338
339impl DirectInputSignal {
340 pub(crate) fn new(pin: AnyPin) -> Self {
341 Self { pin }
342 }
343
344 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
350 connect_pin_to_input_signal(&self.pin, signal, false, false);
351 }
352
353 delegate::delegate! {
354 to self.pin {
355 fn pull_direction(&self, pull: Pull);
356 fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
357 fn init_input(&self, pull: Pull);
358 fn is_input_high(&self) -> bool;
359 fn enable_input(&self, on: bool);
360 }
361 }
362}
363
364#[instability::unstable]
368pub struct OutputSignal {
369 pin: AnyPin,
370 is_inverted: bool,
371}
372
373impl<P> From<P> for OutputSignal
374where
375 P: OutputPin,
376{
377 fn from(output: P) -> Self {
378 Self::new(output.degrade())
379 }
380}
381
382impl From<Flex<'static>> for OutputSignal {
383 fn from(output: Flex<'static>) -> Self {
384 Self::new(unsafe { AnyPin::steal(output.pin.number()) })
385 }
386}
387
388impl Peripheral for OutputSignal {
389 type P = Self;
390
391 unsafe fn clone_unchecked(&self) -> Self::P {
392 Self {
393 pin: self.pin.clone_unchecked(),
394 is_inverted: self.is_inverted,
395 }
396 }
397}
398
399impl Sealed for OutputSignal {}
400
401impl OutputSignal {
402 pub(crate) fn new(pin: AnyPin) -> Self {
403 Self {
404 pin,
405 is_inverted: false,
406 }
407 }
408
409 pub fn number(&self) -> u8 {
411 self.pin.number()
412 }
413
414 pub fn invert(&mut self) {
418 self.is_inverted = !self.is_inverted;
419 }
420
421 pub fn inverted(mut self) -> Self {
426 self.invert();
427 self
428 }
429
430 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
432 connect_peripheral_to_output(&self.pin, signal, self.is_inverted, true, true, false);
433 }
434
435 fn disconnect_from_peripheral_output(&self, signal: gpio::OutputSignal) {
441 disconnect_peripheral_output_from_pin(&self.pin, signal);
442 }
443
444 delegate::delegate! {
445 #[instability::unstable]
446 to self.pin {
447 pub fn pull_direction(&self, pull: Pull);
448 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
449 pub fn init_input(&self, pull: Pull);
450 pub fn is_input_high(&self) -> bool;
451 pub fn enable_input(&self, on: bool);
452
453 pub fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
454 pub fn set_to_open_drain_output(&self);
455 pub fn set_to_push_pull_output(&self);
456 pub fn enable_output(&self, on: bool);
457 pub fn set_output_high(&self, on: bool);
458 pub fn set_drive_strength(&self, strength: gpio::DriveStrength);
459 pub fn enable_open_drain(&self, on: bool);
460 pub fn is_set_high(&self) -> bool;
461 }
462 }
463}
464
465struct DirectOutputSignal {
469 pin: AnyPin,
470}
471
472impl DirectOutputSignal {
473 pub(crate) fn new(pin: AnyPin) -> Self {
474 Self { pin }
475 }
476
477 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
479 connect_peripheral_to_output(&self.pin, signal, false, false, true, false);
480 }
481
482 fn disconnect_from_peripheral_output(&self, signal: gpio::OutputSignal) {
488 disconnect_peripheral_output_from_pin(&self.pin, signal);
489 }
490
491 delegate::delegate! {
492 to self.pin {
493 fn pull_direction(&self, pull: Pull);
494 fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
495 fn init_input(&self, pull: Pull);
496 fn is_input_high(&self) -> bool;
497 fn enable_input(&self, on: bool);
498
499 fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
500 fn set_to_open_drain_output(&self);
501 fn set_to_push_pull_output(&self);
502 fn enable_output(&self, on: bool);
503 fn set_output_high(&self, on: bool);
504 fn set_drive_strength(&self, strength: gpio::DriveStrength);
505 fn enable_open_drain(&self, on: bool);
506 fn is_set_high(&self) -> bool;
507 }
508 }
509}
510
511#[derive(Clone)]
512enum InputConnectionInner {
513 Input(InputSignal),
514 DirectInput(DirectInputSignal),
515 Constant(Level),
516}
517
518#[derive(Clone)]
523#[instability::unstable]
524pub struct InputConnection(InputConnectionInner);
525
526impl Peripheral for InputConnection {
527 type P = Self;
528
529 unsafe fn clone_unchecked(&self) -> Self::P {
530 self.clone()
531 }
532}
533
534impl From<InputSignal> for InputConnection {
535 fn from(input: InputSignal) -> Self {
536 Self(InputConnectionInner::Input(input))
537 }
538}
539
540impl From<Level> for InputConnection {
541 fn from(level: Level) -> Self {
542 Self(InputConnectionInner::Constant(level))
543 }
544}
545
546impl From<NoPin> for InputConnection {
547 fn from(_pin: NoPin) -> Self {
548 Self(InputConnectionInner::Constant(Level::Low))
549 }
550}
551
552impl<P> From<P> for InputConnection
553where
554 P: InputPin,
555{
556 fn from(input: P) -> Self {
557 Self(InputConnectionInner::Input(InputSignal::from(input)))
558 }
559}
560
561impl From<OutputSignal> for InputConnection {
562 fn from(output_signal: OutputSignal) -> Self {
563 Self(InputConnectionInner::Input(InputSignal {
564 pin: output_signal.pin,
565 is_inverted: output_signal.is_inverted,
566 }))
567 }
568}
569
570impl From<DirectOutputSignal> for InputConnection {
571 fn from(output_signal: DirectOutputSignal) -> Self {
572 Self(InputConnectionInner::DirectInput(DirectInputSignal::new(
573 output_signal.pin,
574 )))
575 }
576}
577
578impl From<OutputConnection> for InputConnection {
579 fn from(conn: OutputConnection) -> Self {
580 match conn.0 {
581 OutputConnectionInner::Output(inner) => inner.into(),
582 OutputConnectionInner::DirectOutput(inner) => inner.into(),
583 OutputConnectionInner::Constant(inner) => inner.into(),
584 }
585 }
586}
587
588impl From<Flex<'static>> for InputConnection {
589 fn from(pin: Flex<'static>) -> Self {
590 pin.peripheral_input().into()
591 }
592}
593
594impl Sealed for InputConnection {}
595
596impl InputConnection {
597 delegate::delegate! {
598 #[instability::unstable]
599 to match &self.0 {
600 InputConnectionInner::Input(pin) => pin,
601 InputConnectionInner::DirectInput(pin) => pin,
602 InputConnectionInner::Constant(level) => level,
603 } {
604 pub fn pull_direction(&self, pull: Pull);
605 pub fn init_input(&self, pull: Pull);
606 pub fn is_input_high(&self) -> bool;
607 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
608 pub fn enable_input(&self, on: bool);
609
610 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal);
612 }
613 }
614}
615
616enum OutputConnectionInner {
617 Output(OutputSignal),
618 DirectOutput(DirectOutputSignal),
619 Constant(Level),
620}
621
622#[instability::unstable]
627pub struct OutputConnection(OutputConnectionInner);
628
629impl Sealed for OutputConnection {}
630
631impl Peripheral for OutputConnection {
632 type P = Self;
633
634 unsafe fn clone_unchecked(&self) -> Self::P {
635 match self {
636 Self(OutputConnectionInner::Output(signal)) => Self::from(signal.clone_unchecked()),
637 Self(OutputConnectionInner::DirectOutput(signal)) => {
638 Self::from(DirectOutputSignal::new(signal.pin.clone_unchecked()))
639 }
640 Self(OutputConnectionInner::Constant(level)) => Self::from(*level),
641 }
642 }
643}
644
645impl From<NoPin> for OutputConnection {
646 fn from(_pin: NoPin) -> Self {
647 Self(OutputConnectionInner::Constant(Level::Low))
648 }
649}
650
651impl From<Level> for OutputConnection {
652 fn from(level: Level) -> Self {
653 Self(OutputConnectionInner::Constant(level))
654 }
655}
656
657impl<P> From<P> for OutputConnection
658where
659 P: OutputPin,
660{
661 fn from(input: P) -> Self {
662 Self(OutputConnectionInner::Output(OutputSignal::from(input)))
663 }
664}
665
666impl From<OutputSignal> for OutputConnection {
667 fn from(signal: OutputSignal) -> Self {
668 Self(OutputConnectionInner::Output(signal))
669 }
670}
671
672impl From<Flex<'static>> for OutputConnection {
673 fn from(pin: Flex<'static>) -> Self {
674 pin.into_peripheral_output().into()
675 }
676}
677
678impl From<DirectOutputSignal> for OutputConnection {
679 fn from(signal: DirectOutputSignal) -> Self {
680 Self(OutputConnectionInner::DirectOutput(signal))
681 }
682}
683
684impl OutputConnection {
685 delegate::delegate! {
686 #[instability::unstable]
687 to match &self.0 {
688 OutputConnectionInner::Output(pin) => pin,
689 OutputConnectionInner::DirectOutput(pin) => pin,
690 OutputConnectionInner::Constant(level) => level,
691 } {
692 pub fn is_input_high(&self) -> bool;
693 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
694
695 pub fn is_set_high(&self) -> bool;
696 pub fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
697 pub fn pull_direction(&self, pull: Pull);
698 pub fn init_input(&self, pull: Pull);
699 pub fn enable_input(&self, on: bool);
700
701 pub fn set_to_open_drain_output(&self);
702 pub fn set_to_push_pull_output(&self);
703 pub fn enable_output(&self, on: bool);
704 pub fn set_output_high(&self, on: bool);
705 pub fn set_drive_strength(&self, strength: gpio::DriveStrength);
706 pub fn enable_open_drain(&self, on: bool);
707
708 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal);
710 fn disconnect_from_peripheral_output(&self, signal: gpio::OutputSignal);
711 }
712 }
713
714 pub(crate) fn connect_with_guard(
715 this: impl Peripheral<P = impl PeripheralOutput>,
716 signal: crate::gpio::OutputSignal,
717 ) -> PinGuard {
718 crate::into_mapped_ref!(this);
719 match &this.0 {
720 OutputConnectionInner::Output(pin) => {
721 PinGuard::new(unsafe { pin.pin.clone_unchecked() }, signal)
722 }
723 OutputConnectionInner::DirectOutput(pin) => {
724 PinGuard::new(unsafe { pin.pin.clone_unchecked() }, signal)
725 }
726 OutputConnectionInner::Constant(_) => PinGuard::new_unconnected(signal),
727 }
728 }
729}