1 | use super::io_pin::*; |
2 | #[cfg (any(tsc_v2, tsc_v3))] |
3 | use super::pin_groups::G7; |
4 | #[cfg (tsc_v3)] |
5 | use super::pin_groups::G8; |
6 | use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; |
7 | use super::types::{Group, GroupStatus}; |
8 | use super::TSC_NUM_GROUPS; |
9 | |
10 | /// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. |
11 | /// |
12 | /// This struct holds optional `tsc::IOPin` values for each TSC group, allowing for flexible |
13 | /// configuration of TSC acquisition banks. Each field corresponds to a specific TSC group |
14 | /// and can be set to `Some(tsc::IOPin)` if that group is to be included in the acquisition, |
15 | /// or `None` if it should be excluded. |
16 | #[allow (missing_docs)] |
17 | #[derive (Default)] |
18 | pub struct AcquisitionBankPins { |
19 | pub g1_pin: Option<IOPinWithRole<G1, pin_roles::Channel>>, |
20 | pub g2_pin: Option<IOPinWithRole<G2, pin_roles::Channel>>, |
21 | pub g3_pin: Option<IOPinWithRole<G3, pin_roles::Channel>>, |
22 | pub g4_pin: Option<IOPinWithRole<G4, pin_roles::Channel>>, |
23 | pub g5_pin: Option<IOPinWithRole<G5, pin_roles::Channel>>, |
24 | pub g6_pin: Option<IOPinWithRole<G6, pin_roles::Channel>>, |
25 | #[cfg (any(tsc_v2, tsc_v3))] |
26 | pub g7_pin: Option<IOPinWithRole<G7, pin_roles::Channel>>, |
27 | #[cfg (tsc_v3)] |
28 | pub g8_pin: Option<IOPinWithRole<G8, pin_roles::Channel>>, |
29 | } |
30 | |
31 | impl AcquisitionBankPins { |
32 | /// Returns an iterator over the pins in this acquisition bank. |
33 | /// |
34 | /// This method allows for easy traversal of all configured pins in the bank. |
35 | pub fn iter(&self) -> AcquisitionBankPinsIterator { |
36 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) |
37 | } |
38 | } |
39 | |
40 | /// Iterator for TSC acquisition banks. |
41 | /// |
42 | /// This iterator allows traversing through the pins of a `AcquisitionBankPins` struct, |
43 | /// yielding each configured pin in order of the TSC groups. |
44 | pub struct AcquisitionBankIterator<'a> { |
45 | pins: &'a AcquisitionBankPins, |
46 | current_group: u8, |
47 | } |
48 | |
49 | impl<'a> AcquisitionBankIterator<'a> { |
50 | fn new(pins: &'a AcquisitionBankPins) -> Self { |
51 | Self { pins, current_group: 0 } |
52 | } |
53 | |
54 | fn next_pin(&mut self) -> Option<IOPin> { |
55 | while self.current_group < TSC_NUM_GROUPS as u8 { |
56 | let pin = match self.current_group { |
57 | 0 => self.pins.g1_pin.map(IOPinWithRole::get_pin), |
58 | 1 => self.pins.g2_pin.map(IOPinWithRole::get_pin), |
59 | 2 => self.pins.g3_pin.map(IOPinWithRole::get_pin), |
60 | 3 => self.pins.g4_pin.map(IOPinWithRole::get_pin), |
61 | 4 => self.pins.g5_pin.map(IOPinWithRole::get_pin), |
62 | 5 => self.pins.g6_pin.map(IOPinWithRole::get_pin), |
63 | #[cfg (any(tsc_v2, tsc_v3))] |
64 | 6 => self.pins.g7_pin.map(IOPinWithRole::get_pin), |
65 | #[cfg (tsc_v3)] |
66 | 7 => self.pins.g8_pin.map(IOPinWithRole::get_pin), |
67 | _ => None, |
68 | }; |
69 | self.current_group += 1; |
70 | if pin.is_some() { |
71 | return pin; |
72 | } |
73 | } |
74 | None |
75 | } |
76 | } |
77 | |
78 | /// Iterator for TSC acquisition bank pins. |
79 | /// |
80 | /// This iterator yields `tsc::IOPin` values for each configured pin in the acquisition bank. |
81 | pub struct AcquisitionBankPinsIterator<'a>(AcquisitionBankIterator<'a>); |
82 | |
83 | impl<'a> Iterator for AcquisitionBankPinsIterator<'a> { |
84 | type Item = IOPin; |
85 | |
86 | fn next(&mut self) -> Option<Self::Item> { |
87 | self.0.next_pin() |
88 | } |
89 | } |
90 | |
91 | impl AcquisitionBankPins { |
92 | /// Returns an iterator over the available pins in the bank |
93 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { |
94 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) |
95 | } |
96 | } |
97 | |
98 | /// Represents a collection of TSC pins to be acquired simultaneously. |
99 | /// |
100 | /// This struct contains a set of pins to be used in a TSC acquisition with a pre-computed and |
101 | /// verified mask for efficiently setting up the TSC peripheral before performing an acquisition. |
102 | /// It ensures that only one channel pin per TSC group is included, adhering to hardware limitations. |
103 | pub struct AcquisitionBank { |
104 | pub(super) pins: AcquisitionBankPins, |
105 | pub(super) mask: u32, |
106 | } |
107 | |
108 | impl AcquisitionBank { |
109 | /// Returns an iterator over the available pins in the bank. |
110 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { |
111 | self.pins.pins_iterator() |
112 | } |
113 | |
114 | /// Returns the mask for this bank. |
115 | pub fn mask(&self) -> u32 { |
116 | self.mask |
117 | } |
118 | |
119 | /// Retrieves the TSC I/O pin for a given group in this acquisition bank. |
120 | /// |
121 | /// # Arguments |
122 | /// * `group` - The TSC group to retrieve the pin for. |
123 | /// |
124 | /// # Returns |
125 | /// An `Option<tsc::IOPin>` containing the pin if it exists for the given group, or `None` if not. |
126 | pub fn get_pin(&self, group: Group) -> Option<IOPin> { |
127 | match group { |
128 | Group::One => self.pins.g1_pin.map(|p| p.pin), |
129 | Group::Two => self.pins.g2_pin.map(|p| p.pin), |
130 | Group::Three => self.pins.g3_pin.map(|p| p.pin), |
131 | Group::Four => self.pins.g4_pin.map(|p| p.pin), |
132 | Group::Five => self.pins.g5_pin.map(|p| p.pin), |
133 | Group::Six => self.pins.g6_pin.map(|p| p.pin), |
134 | #[cfg (any(tsc_v2, tsc_v3))] |
135 | Group::Seven => self.pins.g7_pin.map(|p| p.pin), |
136 | #[cfg (tsc_v3)] |
137 | Group::Eight => self.pins.g8_pin.map(|p| p.pin), |
138 | } |
139 | } |
140 | } |
141 | |
142 | /// Represents the status of all TSC groups in an acquisition bank |
143 | #[derive (Default)] |
144 | pub struct AcquisitionBankStatus { |
145 | pub(super) groups: [Option<GroupStatus>; TSC_NUM_GROUPS], |
146 | } |
147 | |
148 | impl AcquisitionBankStatus { |
149 | /// Check if all groups in the bank are complete |
150 | pub fn all_complete(&self) -> bool { |
151 | self.groups |
152 | .iter() |
153 | .all(|&status| status.map_or(true, |s| s == GroupStatus::Complete)) |
154 | } |
155 | |
156 | /// Check if any group in the bank is ongoing |
157 | pub fn any_ongoing(&self) -> bool { |
158 | self.groups.iter().any(|&status| status == Some(GroupStatus::Ongoing)) |
159 | } |
160 | |
161 | /// Get the status of a specific group, if the group is present in the bank |
162 | pub fn get_group_status(&self, group: Group) -> Option<GroupStatus> { |
163 | let index: usize = group.into(); |
164 | self.groups[index] |
165 | } |
166 | |
167 | /// Iterator for groups present in the bank |
168 | pub fn iter(&self) -> impl Iterator<Item = (Group, GroupStatus)> + '_ { |
169 | self.groups.iter().enumerate().filter_map(|(group_num, status)| { |
170 | status.and_then(|s| Group::try_from(group_num).ok().map(|group| (group, s))) |
171 | }) |
172 | } |
173 | } |
174 | |
175 | /// Represents the result of a Touch Sensing Controller (TSC) acquisition for a specific pin. |
176 | /// |
177 | /// This struct contains a reference to the `tsc::IOPin` from which a value was read, |
178 | /// along with the actual sensor reading for that pin. It provides a convenient way |
179 | /// to associate TSC readings with their corresponding pins after an acquisition. |
180 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
181 | #[derive (Clone, Copy, Debug)] |
182 | pub struct ChannelReading { |
183 | /// The sensor reading value obtained from the TSC acquisition. |
184 | /// Lower values typically indicate a detected touch, while higher values indicate no touch. |
185 | pub sensor_value: u16, |
186 | |
187 | /// The `tsc::IOPin` associated with this reading. |
188 | /// This allows for easy identification of which pin the reading corresponds to. |
189 | pub tsc_pin: IOPin, |
190 | } |
191 | |
192 | /// Represents the readings from all TSC groups |
193 | #[derive (Default)] |
194 | pub struct AcquisitionBankReadings { |
195 | pub(super) groups: [Option<ChannelReading>; TSC_NUM_GROUPS], |
196 | } |
197 | |
198 | impl AcquisitionBankReadings { |
199 | /// Get the reading for a specific group, if the group is present in the bank |
200 | pub fn get_group_reading(&self, group: Group) -> Option<ChannelReading> { |
201 | let index: usize = group.into(); |
202 | self.groups[index] |
203 | } |
204 | |
205 | /// Iterator for readings for groups present in the bank |
206 | pub fn iter(&self) -> impl Iterator<Item = ChannelReading> + '_ { |
207 | self.groups.iter().filter_map(|&x: Option| x) |
208 | } |
209 | } |
210 | |