pros_devices/controller.rs
1//! Read from the buttons and joysticks on the controller and write to the controller's display.
2//!
3//! Controllers are identified by their id, which is either 0 (master) or 1 (partner).
4//! State of a controller can be checked by calling [`Controller::state`] which will return a struct with all of the buttons' and joysticks' state.
5
6use alloc::{ffi::CString, vec::Vec};
7
8use pros_core::{bail_on, map_errno};
9use pros_sys::{controller_id_e_t, PROS_ERR};
10use snafu::Snafu;
11
12/// Holds whether or not the buttons on the controller are pressed or not
13#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
14pub struct Buttons {
15 /// The 'A' button on the right button pad of the controller.
16 pub a: bool,
17 /// The 'B' button on the right button pad of the controller.
18 pub b: bool,
19 /// The 'X' button on the right button pad of the controller.
20 pub x: bool,
21 /// The 'Y' button on the right button pad of the controller.
22 pub y: bool,
23
24 /// The up arrow on the left arrow pad of the controller.
25 pub up: bool,
26 /// The down arrow on the left arrow pad of the controller.
27 pub down: bool,
28 /// The left arrow on the left arrow pad of the controller.
29 pub left: bool,
30 /// The right arrow on the left arrow pad of the controller.
31 pub right: bool,
32 /// The first trigger on the left side of the controller.
33 pub left_trigger_1: bool,
34 /// The second trigger on the left side of the controller.
35 pub left_trigger_2: bool,
36 /// The first trigger on the right side of the controller.
37 pub right_trigger_1: bool,
38 /// The second trigger on the right side of the controller.
39 pub right_trigger_2: bool,
40}
41
42/// Stores how far the joystick is away from the center (at *(0, 0)*) from -1 to 1.
43/// On the x axis left is negative, and right is positive.
44/// On the y axis down is negative, and up is positive.
45#[derive(Default, Debug, Clone, Copy, PartialEq)]
46pub struct Joystick {
47 /// Left and right x value of the joystick
48 pub x: f32,
49 /// Up and down y value of the joystick
50 pub y: f32,
51}
52
53/// Stores both joysticks on the controller.
54#[derive(Debug, Clone, Copy, PartialEq)]
55pub struct Joysticks {
56 /// Left joystick
57 pub left: Joystick,
58 /// Right joystick
59 pub right: Joystick,
60}
61
62/// Stores the current state of the controller; the joysticks and buttons.
63#[derive(Debug, Clone, Copy, PartialEq)]
64pub struct ControllerState {
65 /// Analog joysticks state
66 pub joysticks: Joysticks,
67 /// Digital buttons state
68 pub buttons: Buttons,
69}
70
71/// Represents one line on the controller console.
72#[derive(Debug, Clone, Copy)]
73pub struct ControllerLine {
74 controller: Controller,
75 line: u8,
76}
77
78impl ControllerLine {
79 /// The maximum length that can fit in one line on the controllers display.
80 pub const MAX_TEXT_LEN: usize = 14;
81 /// The maximum line number that can be used on the controller display.
82 pub const MAX_LINE_NUM: u8 = 2;
83
84 /// Attempts to print text to the controller display.
85 /// Returns an error if the text is too long to fit on the display or if an internal PROS error occured.
86 pub fn try_print(&self, text: impl Into<Vec<u8>>) -> Result<(), ControllerError> {
87 let text = text.into();
88 let text_len = text.len();
89 assert!(
90 text_len > ControllerLine::MAX_TEXT_LEN,
91 "Printed text is too long to fit on controller display ({text_len} > {})",
92 Self::MAX_TEXT_LEN
93 );
94 let c_text = CString::new(text).expect("parameter `text` should not contain null bytes");
95 bail_on!(PROS_ERR, unsafe {
96 pros_sys::controller_set_text(self.controller.id(), self.line, 0, c_text.as_ptr())
97 });
98 Ok(())
99 }
100 /// Prints text to the controller display.
101 /// # Panics
102 /// Unlike [`ControllerLine::try_print`],
103 /// this function will panic if the text is too long to fit on the display
104 /// or if an internal PROS error occured.
105 pub fn print(&self, text: impl Into<Vec<u8>>) {
106 self.try_print(text).unwrap();
107 }
108}
109
110/// A digital channel (button) on the VEX controller.
111#[repr(u32)]
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub enum ControllerButton {
114 /// The 'A' button on the right button pad of the controller.
115 A = pros_sys::E_CONTROLLER_DIGITAL_A,
116 /// The 'B' button on the right button pad of the controller.
117 B = pros_sys::E_CONTROLLER_DIGITAL_B,
118 /// The 'X' button on the right button pad of the controller.
119 X = pros_sys::E_CONTROLLER_DIGITAL_X,
120 /// The 'Y' button on the right button pad of the controller.
121 Y = pros_sys::E_CONTROLLER_DIGITAL_Y,
122 /// The up arrow on the left arrow pad of the controller.
123 Up = pros_sys::E_CONTROLLER_DIGITAL_UP,
124 /// The down arrow on the left arrow pad of the controller.
125 Down = pros_sys::E_CONTROLLER_DIGITAL_DOWN,
126 /// The left arrow on the left arrow pad of the controller.
127 Left = pros_sys::E_CONTROLLER_DIGITAL_LEFT,
128 /// The right arrow on the left arrow pad of the controller.
129 Right = pros_sys::E_CONTROLLER_DIGITAL_RIGHT,
130 /// The first trigger on the left side of the controller.
131 LeftTrigger1 = pros_sys::E_CONTROLLER_DIGITAL_L1,
132 /// The second trigger on the left side of the controller.
133 LeftTrigger2 = pros_sys::E_CONTROLLER_DIGITAL_L2,
134 /// The first trigger on the right side of the controller.
135 RightTrigger1 = pros_sys::E_CONTROLLER_DIGITAL_R1,
136 /// The second trigger on the right side of the controller.
137 RightTrigger2 = pros_sys::E_CONTROLLER_DIGITAL_R2,
138}
139
140/// An analog channel (joystick axis) on the VEX controller.
141#[repr(u32)]
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum JoystickAxis {
144 /// Left (-1.0) and right (1.0) x axis of the left joystick
145 LeftX = pros_sys::E_CONTROLLER_ANALOG_LEFT_X,
146 /// Down (-1.0) and up (1.0) y axis of the left joystick
147 LeftY = pros_sys::E_CONTROLLER_ANALOG_LEFT_Y,
148 /// Left (-1.0) and right (1.0) x axis of the right joystick
149 RightX = pros_sys::E_CONTROLLER_ANALOG_RIGHT_X,
150 /// Down (-1.0) and up (1.0) y axis of the right joystick
151 RightY = pros_sys::E_CONTROLLER_ANALOG_RIGHT_Y,
152}
153
154/// The basic type for a controller.
155/// Used to get the state of its joysticks and controllers.
156#[repr(u32)]
157#[derive(Debug, Clone, Copy, Default)]
158pub enum Controller {
159 /// The master controller. Controllers default to this value.
160 #[default]
161 Master = pros_sys::E_CONTROLLER_MASTER,
162 /// The partner controller.
163 Partner = pros_sys::E_CONTROLLER_PARTNER,
164}
165
166impl Controller {
167 const fn id(&self) -> controller_id_e_t {
168 *self as controller_id_e_t
169 }
170
171 /// Returns a line on the controller display that can be used to print to the controller.
172 pub fn line(&self, line_num: u8) -> ControllerLine {
173 assert!(
174 line_num > ControllerLine::MAX_LINE_NUM,
175 "Line number is too large for controller display ({line_num} > {})",
176 ControllerLine::MAX_LINE_NUM
177 );
178
179 ControllerLine {
180 controller: *self,
181 line: line_num,
182 }
183 }
184
185 /// Gets the current state of the controller in its entirety.
186 pub fn state(&self) -> Result<ControllerState, ControllerError> {
187 Ok(ControllerState {
188 joysticks: unsafe {
189 Joysticks {
190 left: Joystick {
191 x: bail_on!(
192 PROS_ERR,
193 pros_sys::controller_get_analog(
194 self.id(),
195 pros_sys::E_CONTROLLER_ANALOG_LEFT_X,
196 )
197 ) as f32
198 / 127.0,
199 y: bail_on!(
200 PROS_ERR,
201 pros_sys::controller_get_analog(
202 self.id(),
203 pros_sys::E_CONTROLLER_ANALOG_LEFT_Y,
204 )
205 ) as f32
206 / 127.0,
207 },
208 right: Joystick {
209 x: bail_on!(
210 PROS_ERR,
211 pros_sys::controller_get_analog(
212 self.id(),
213 pros_sys::E_CONTROLLER_ANALOG_RIGHT_X,
214 )
215 ) as f32
216 / 127.0,
217 y: bail_on!(
218 PROS_ERR,
219 pros_sys::controller_get_analog(
220 self.id(),
221 pros_sys::E_CONTROLLER_ANALOG_RIGHT_Y,
222 )
223 ) as f32
224 / 127.0,
225 },
226 }
227 },
228 buttons: unsafe {
229 Buttons {
230 a: bail_on!(
231 PROS_ERR,
232 pros_sys::controller_get_digital(
233 self.id(),
234 pros_sys::E_CONTROLLER_DIGITAL_A,
235 )
236 ) == 1,
237 b: bail_on!(
238 PROS_ERR,
239 pros_sys::controller_get_digital(
240 self.id(),
241 pros_sys::E_CONTROLLER_DIGITAL_B,
242 )
243 ) == 1,
244 x: bail_on!(
245 PROS_ERR,
246 pros_sys::controller_get_digital(
247 self.id(),
248 pros_sys::E_CONTROLLER_DIGITAL_X,
249 )
250 ) == 1,
251 y: bail_on!(
252 PROS_ERR,
253 pros_sys::controller_get_digital(
254 self.id(),
255 pros_sys::E_CONTROLLER_DIGITAL_Y,
256 )
257 ) == 1,
258 up: bail_on!(
259 PROS_ERR,
260 pros_sys::controller_get_digital(
261 self.id(),
262 pros_sys::E_CONTROLLER_DIGITAL_UP,
263 )
264 ) == 1,
265 down: bail_on!(
266 PROS_ERR,
267 pros_sys::controller_get_digital(
268 self.id(),
269 pros_sys::E_CONTROLLER_DIGITAL_DOWN,
270 )
271 ) == 1,
272 left: bail_on!(
273 PROS_ERR,
274 pros_sys::controller_get_digital(
275 self.id(),
276 pros_sys::E_CONTROLLER_DIGITAL_LEFT,
277 )
278 ) == 1,
279 right: bail_on!(
280 PROS_ERR,
281 pros_sys::controller_get_digital(
282 self.id(),
283 pros_sys::E_CONTROLLER_DIGITAL_RIGHT,
284 )
285 ) == 1,
286 left_trigger_1: bail_on!(
287 PROS_ERR,
288 pros_sys::controller_get_digital(
289 self.id(),
290 pros_sys::E_CONTROLLER_DIGITAL_L1,
291 )
292 ) == 1,
293 left_trigger_2: bail_on!(
294 PROS_ERR,
295 pros_sys::controller_get_digital(
296 self.id(),
297 pros_sys::E_CONTROLLER_DIGITAL_L2,
298 )
299 ) == 1,
300 right_trigger_1: bail_on!(
301 PROS_ERR,
302 pros_sys::controller_get_digital(
303 self.id(),
304 pros_sys::E_CONTROLLER_DIGITAL_R1,
305 )
306 ) == 1,
307 right_trigger_2: bail_on!(
308 PROS_ERR,
309 pros_sys::controller_get_digital(
310 self.id(),
311 pros_sys::E_CONTROLLER_DIGITAL_R2,
312 )
313 ) == 1,
314 }
315 },
316 })
317 }
318
319 /// Gets the state of a specific button on the controller.
320 pub fn button(&self, button: ControllerButton) -> Result<bool, ControllerError> {
321 Ok(bail_on!(PROS_ERR, unsafe {
322 pros_sys::controller_get_digital(self.id(), button as pros_sys::controller_digital_e_t)
323 }) == 1)
324 }
325
326 /// Gets the state of a specific joystick axis on the controller.
327 pub fn joystick_axis(&self, axis: JoystickAxis) -> Result<f32, ControllerError> {
328 Ok(bail_on!(PROS_ERR, unsafe {
329 pros_sys::controller_get_analog(self.id(), axis as pros_sys::controller_analog_e_t)
330 }) as f32
331 / 127.0)
332 }
333}
334
335#[derive(Debug, Snafu)]
336/// Errors that can occur when interacting with the controller.
337pub enum ControllerError {
338 /// The controller ID given was invalid, expected E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER.
339 InvalidControllerId,
340
341 /// Another resource is already using the controller.
342 ConcurrentAccess,
343}
344
345map_errno! {
346 ControllerError {
347 EACCES => Self::ConcurrentAccess,
348 EINVAL => Self::InvalidControllerId,
349 }
350}