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 {}