lpc8xx_hal/swm/
functions.rs

1use core::marker::PhantomData;
2
3use crate::pins::{self, Pin};
4
5use super::{
6    assignment::{AssignFunction, UnassignFunction},
7    function_kind::FunctionKind,
8    handle::Handle,
9    state::{Assigned, State, Unassigned},
10};
11
12/// A fixed or movable function that can be assigned to a pin
13///
14/// The type parameter `T` identifies the fixed or movable function that an
15/// instance of `Function` controls. The other type paramter, `State`, tracks
16/// whether this function is assigned to a pin, and which pin it is assigned to.
17///
18/// You can gain access to the instances of this struct that represent fixed
19/// functions through [`FixedFunctions`], to those that represent movable
20/// functions through [`MovableFunctions`].
21///
22/// [`FixedFunctions`]: struct.FixedFunctions.html
23/// [`MovableFunctions`]: struct.MovableFunctions.html
24pub struct Function<T, S> {
25    ty: T,
26    _state: S,
27}
28
29impl<T, S> Function<T, S>
30where
31    S: State,
32{
33    pub(crate) fn new(ty: T) -> Self {
34        Self {
35            ty,
36            _state: S::new(),
37        }
38    }
39}
40
41impl<T> Function<T, Unassigned> {
42    /// Assign this function to a pin
43    ///
44    /// This method is only available if a number of requirements are met:
45    /// - `Function` must be in the [`Unassigned`] state, as a function can only
46    ///   be assigned to one pin.
47    /// - The [`Pin`] must be in the SWM state ([`pins::state::Swm`]). See
48    ///   documentation on [`Pin`] for information on pin state management.
49    /// - The function must be assignable to the pin. Movable functions can be
50    ///   assigned to any pin, but fixed functions can be assigned to only one
51    ///   specific pin.
52    /// - The state of the pin must allow another function of this type to be
53    ///   assigned. Input functions can always be assigned, but only one output
54    ///   or bidirectional function can be assigned to a given pin at any time.
55    ///
56    /// Code attempting to call this method while these requirement are not met,
57    /// will not compile.
58    ///
59    /// Consumes this instance of `Function`, as well as the provided [`Pin`],
60    /// and returns new instances. The returned `Function` instance will have its
61    /// state set to indicate that it has been assigned to the pin. The returned
62    /// [`Pin`] will have its state updated to indicate that a function of this
63    /// `Function`'s type has been assigned.
64    ///
65    /// # Examples
66    ///
67    /// Assign one output and one input function to the same pin:
68    ///
69    /// ``` no_run
70    /// use lpc8xx_hal::Peripherals;
71    ///
72    /// let p = Peripherals::take().unwrap();
73    ///
74    /// let mut syscon = p.SYSCON.split();
75    /// let mut swm = p.SWM.split();
76    ///
77    /// #[cfg(feature = "82x")]
78    /// let mut swm_handle = swm.handle;
79    /// #[cfg(feature = "845")]
80    /// let mut swm_handle = swm.handle.enable(&mut syscon.handle);
81    ///
82    /// // Assign output function to a pin
83    /// let (u0_txd, pio0_0) = swm.movable_functions.u0_txd.assign(
84    ///     p.pins.pio0_0.into_swm_pin(),
85    ///     &mut swm_handle,
86    /// );
87    ///
88    /// // Assign input function to the same pin
89    /// let (u1_rxd, pio0_0) = swm.movable_functions.u1_rxd.assign(
90    ///     pio0_0,
91    ///     &mut swm_handle,
92    /// );
93    /// ```
94    ///
95    /// [`Unassigned`]: state/struct.Unassigned.html
96    /// [`Pin`]: ../pins/struct.Pin.html
97    /// [`pins::state::Swm`]: ../pins/state/struct.Swm.html
98    pub fn assign<P, S>(
99        mut self,
100        mut pin: Pin<P, S>,
101        swm: &mut Handle,
102    ) -> (
103        Function<T, Assigned<P>>,
104        <Pin<P, S> as AssignFunction<T, T::Kind>>::Assigned,
105    )
106    where
107        T: FunctionTrait<P>,
108        P: pins::Trait,
109        S: pins::State,
110        Pin<P, S>: AssignFunction<T, T::Kind>,
111    {
112        self.ty.assign(&mut pin.ty, swm);
113
114        let function = Function {
115            ty: self.ty,
116            _state: Assigned(PhantomData),
117        };
118
119        (function, pin.assign())
120    }
121}
122
123impl<T, P> Function<T, Assigned<P>> {
124    /// Unassign this function from a pin
125    ///
126    /// This method is only available if a number of requirements are met:
127    /// - The function must be assigned to the provided pin. This means
128    ///   `Function` must be in the [`Assigned`] state, and the type parameter
129    ///   of [`Assigned`] must indicate that the function is assigned to the
130    ///   same pin that is provided as an argument.
131    /// - The [`Pin`] must be in the SWM state ([`pins::state::Swm`]), and the
132    ///   state must indicate that a function of this `Function`'s type is
133    ///   currently assigned. This should always be the case, if the previous
134    ///   condition is met, as it should be impossible to create inconsistent
135    ///   states between `Function`s and [`Pin`]s without using `unsafe`.
136    ///
137    /// Code attempting to call this method while these requirement are not met,
138    /// will not compile.
139    ///
140    /// Consumes this instance of `Function`, as well as the provided [`Pin`],
141    /// and returns new instances. The returned `Function` instance will have
142    /// its state set to indicate that it is no longer assigned to a pin. The
143    /// returned [`Pin`] will have its state updated to indicate that one fewer
144    /// function of this type is now assigned.
145    ///
146    /// # Examples
147    ///
148    /// Unassign a function that has been previously assigned to a pin:
149    ///
150    /// ``` no_run
151    /// # use lpc8xx_hal::Peripherals;
152    /// #
153    /// # let p = Peripherals::take().unwrap();
154    /// #
155    /// # let mut swm = p.SWM.split();
156    /// # let mut syscon = p.SYSCON.split();
157    /// #
158    /// # #[cfg(feature = "82x")]
159    /// # let mut swm_handle = swm.handle;
160    /// # #[cfg(feature = "845")]
161    /// # let mut swm_handle = swm.handle.enable(&mut syscon.handle);
162    /// #
163    /// # // Assign output function to a pin
164    /// # let (u0_txd, pio0_0) = swm.movable_functions.u0_txd.assign(
165    /// #     p.pins.pio0_0.into_swm_pin(),
166    /// #     &mut swm_handle,
167    /// # );
168    /// #
169    /// // U0_TXD must have been previously assigned to the pin, or the
170    /// // following code will not compile. See documentation of
171    /// // `Function::assign`.
172    /// let (u0_txd, pio0_0) = u0_txd.unassign(pio0_0, &mut swm_handle);
173    /// ```
174    ///
175    /// [`Assigned`]: state/struct.Assigned.html
176    /// [`Pin`]: ../pins/struct.Pin.html
177    /// [`pins::state::Swm`]: ../pins/state/struct.Swm.html
178    pub fn unassign<S>(
179        mut self,
180        mut pin: Pin<P, S>,
181        swm: &mut Handle,
182    ) -> (
183        Function<T, Unassigned>,
184        <Pin<P, S> as UnassignFunction<T, T::Kind>>::Unassigned,
185    )
186    where
187        T: FunctionTrait<P>,
188        P: pins::Trait,
189        S: pins::State,
190        Pin<P, S>: UnassignFunction<T, T::Kind>,
191    {
192        self.ty.unassign(&mut pin.ty, swm);
193
194        let function = Function {
195            ty: self.ty,
196            _state: Unassigned,
197        };
198
199        (function, pin.unassign())
200    }
201}
202
203/// Implemented for all fixed and movable functions
204///
205/// This trait is an internal implementation detail and should neither be
206/// implemented nor used outside of LPC8xx HAL. Any changes to this trait won't
207/// be considered breaking changes.
208///
209/// Please refer [`Function::assign`] and [`Function::unassign`] for the public
210/// API that uses this trait.
211///
212/// [`Function::assign`]: struct.Function.html#method.assign
213/// [`Function::unassign`]: struct.Function.html#method.unassign
214pub trait FunctionTrait<P: pins::Trait> {
215    /// Whether this is an input or output function
216    ///
217    /// There are also bidirectional functions, but for our purposes, they are
218    /// treated as output functions.
219    type Kind: FunctionKind;
220
221    /// Internal method to assign a function to a pin
222    fn assign(&mut self, pin: &mut P, swm: &mut Handle);
223
224    /// Internal method to unassign a function from a pin
225    fn unassign(&mut self, pin: &mut P, swm: &mut Handle);
226}
227
228/// Used as a placeholder, to indicate that an SWM function is not available
229pub enum NotAvailable {}