robot_hat_rs/
pin.rs

1//! Pin abstraction layer for robot-hat
2
3use anyhow::{Context, Result};
4use rppal::gpio::{self, Gpio};
5
6const BOARD_TYPE: u8 = 12;
7
8fn check_board_type() -> Result<bool> {
9    let type_pin = Gpio::new()?.get(BOARD_TYPE)?.into_input();
10
11    Ok(type_pin.is_low())
12}
13
14/// An explicit allowable types for [`RHPin`]
15#[derive(Copy, Clone, Debug)]
16pub enum PinType {
17    /// The Digital pin 0
18    D0,
19    /// The Digital pin 1
20    D1,
21    /// The Digital pin 2
22    D2,
23    /// The Digital pin 3
24    D3,
25    /// The Digital pin 4
26    D4,
27    /// The Digital pin 5
28    D5,
29    /// The Digital pin 6
30    D6,
31    /// The Digital pin 7
32    D7,
33    /// The Digital pin 8
34    D8,
35    /// The Digital pin 9
36    D9,
37    /// The Digital pin 10
38    D10,
39    /// The Digital pin 11
40    D11,
41    /// The Digital pin 12
42    D12,
43    /// The Digital pin 13
44    D13,
45    /// The Digital pin 14
46    D14,
47    /// The Digital pin 15
48    D15,
49    /// The Digital pin 16
50    D16,
51    /// The Analog pin 0
52    A0,
53    /// The Analog pin 1
54    A1,
55    /// The Analog pin 2
56    A2,
57    /// The Analog pin 3
58    A3,
59    /// The Analog pin 4
60    A4,
61    /// The Analog pin 5
62    A5,
63    /// The Analog pin 6
64    A6,
65    /// The Analog pin 7
66    A7,
67    /// The Pwm pin 0
68    P0,
69    /// The Pwm pin 1
70    P1,
71    /// The Pwm pin 2
72    P2,
73    /// The Pwm pin 3
74    P3,
75    /// The Pwm pin 4
76    P4,
77    /// The Pwm pin 5
78    P5,
79    /// The Pwm pin 6
80    P6,
81    /// The Pwm pin 7
82    P7,
83    /// The Pwm pin 8
84    P8,
85    /// The Pwm pin 9
86    P9,
87    /// The Pwm pin 10
88    P10,
89    /// The Pwm pin 11
90    P11,
91    /// The Pwm pin 12
92    P12,
93    /// The Pwm pin 13
94    P13,
95    /// The USR button
96    SW,
97    /// The USR button
98    User,
99    /// The LED on the board
100    Led,
101    /// The board type pin
102    BoardType,
103    /// The Reset pin
104    Rst,
105    /// The Ble interrupt pin ?
106    BleInt,
107    /// The Ble reset pin ?
108    BleRst,
109    /// The MCU reset pin
110    McuRst,
111}
112
113impl PinType {
114    fn bcm_num(&self, board_type: bool) -> u8 {
115        match self {
116            PinType::D0 => 17,
117            PinType::D1 => {
118                if board_type {
119                    18
120                } else {
121                    4
122                }
123            }
124            PinType::D2 => 27,
125            PinType::D3 => 22,
126            PinType::D4 => 23,
127            PinType::D5 => 24,
128            PinType::D6 => 25,
129            PinType::D7 => 4,
130            PinType::D8 => 5,
131            PinType::D9 => 6,
132            PinType::D10 => 12,
133            PinType::D11 => 13,
134            PinType::D12 => 19,
135            PinType::D13 => 16,
136            PinType::D14 => 26,
137            PinType::D15 => 20,
138            PinType::D16 => 21,
139            PinType::SW => {
140                if board_type {
141                    19
142                } else {
143                    25
144                }
145            }
146            PinType::User => {
147                if board_type {
148                    19
149                } else {
150                    25
151                }
152            }
153            PinType::Led => 26,
154            PinType::BoardType => 12,
155            PinType::Rst => 16,
156            PinType::BleInt => 13,
157            PinType::BleRst => 20,
158            PinType::McuRst => {
159                if board_type {
160                    21
161                } else {
162                    5
163                }
164            }
165            _ => panic!("Cannot find bcm number for {:?}", self),
166        }
167    }
168
169    /// checks if `PinType` is a Digital Pin
170    pub fn is_digital_pin(&self) -> bool {
171        matches!(
172            self,
173            PinType::D0
174                | PinType::D1
175                | PinType::D2
176                | PinType::D3
177                | PinType::D4
178                | PinType::D5
179                | PinType::D6
180                | PinType::D7
181                | PinType::D8
182                | PinType::D9
183                | PinType::D10
184                | PinType::D11
185                | PinType::D12
186                | PinType::D13
187                | PinType::D14
188                | PinType::D15
189                | PinType::D16
190        )
191    }
192
193    /// checks if `PinType` is a Analog Pin
194    pub fn is_adc_pin(&self) -> bool {
195        matches!(
196            self,
197            PinType::D0
198                | PinType::A0
199                | PinType::A1
200                | PinType::A2
201                | PinType::A3
202                | PinType::A4
203                | PinType::A5
204                | PinType::A6
205                | PinType::A7
206        )
207    }
208
209    /// checks if `PinType` is a Pwm pin
210    pub fn is_pwm_pin(&self) -> bool {
211        matches!(
212            self,
213            PinType::P0
214                | PinType::P1
215                | PinType::P2
216                | PinType::P3
217                | PinType::P4
218                | PinType::P5
219                | PinType::P6
220                | PinType::P7
221                | PinType::P8
222                | PinType::P9
223                | PinType::P10
224                | PinType::P11
225                | PinType::P12
226                | PinType::P13
227        )
228    }
229
230    /// Get channel number for ADC pin `PinType::A0-A7`
231    pub fn adc_channel(&self) -> u8 {
232        match self {
233            PinType::A0 => 0,
234            PinType::A1 => 1,
235            PinType::A2 => 2,
236            PinType::A3 => 3,
237            PinType::A4 => 4,
238            PinType::A5 => 5,
239            PinType::A6 => 6,
240            PinType::A7 => 7,
241            _ => panic!("pin should be one of PinType::A0-P7, but passed {:?}", self),
242        }
243    }
244
245    /// Get channel number for Pwm pin `PinType::P0-P13`
246    pub fn pwm_channel(&self) -> u8 {
247        match self {
248            PinType::P0 => 0,
249            PinType::P1 => 1,
250            PinType::P2 => 2,
251            PinType::P3 => 3,
252            PinType::P4 => 4,
253            PinType::P5 => 5,
254            PinType::P6 => 6,
255            PinType::P7 => 7,
256            PinType::P8 => 8,
257            PinType::P9 => 9,
258            PinType::P10 => 10,
259            PinType::P11 => 11,
260            PinType::P12 => 12,
261            PinType::P13 => 13,
262            _ => panic!(
263                "pin should be one of PinType::P0-P13, but passed {:?}",
264                self
265            ),
266        }
267    }
268}
269
270/// A robot-hat pin
271#[derive(Debug)]
272pub struct RHPin {
273    /// A [`gpio::Pin`] from [`rppal`] crate
274    pub gpio_pin: gpio::Pin,
275    /// BCM number of the Pin
276    pub bcm_num: u8,
277}
278
279impl RHPin {
280    /// Create a new robot-hat pin using any [`PinType`]
281    pub fn new(pin_type: PinType) -> Result<Self> {
282        let board_type = check_board_type().context("Checking Board type failed")?;
283        let bcm_num = pin_type.bcm_num(board_type);
284        let gpio_pin = Gpio::new()?.get(bcm_num)?;
285
286        Ok(Self { gpio_pin, bcm_num })
287    }
288}