1use events::{Event, EventHandler, EventMap, HandlerFn};
2use hidapi::{DeviceInfo, HidApi};
3
4use std::{
5 env::consts::OS,
6 ops::BitOr,
7 process::exit,
8 sync::{atomic::AtomicBool, Arc, Mutex, RwLock},
9 thread::{self, sleep},
10 time::Duration,
11};
12
13pub mod events;
14mod state;
16const FRAME_SIZE: usize = 12;
18
19#[derive(Debug, PartialEq, Clone, Eq, Hash)]
24pub enum DpadPosition {
25 Up,
26 TopRight,
27 Right,
28 BottomRight,
29 Down,
30 BottomLeft,
31 Left,
32 TopLeft,
33 None,
34}
35
36type Frame = [u8; FRAME_SIZE];
42
43#[derive(Debug, PartialEq, Clone, Eq, Hash)]
49pub enum GearSelector {
50 Neutral = 0,
51 First = 1,
52 Second = 2,
53 Third = 4,
54 Fourth = 8,
55 Fifth = 16,
56 Sixth = 32,
57 Reverse = 64,
58}
59
60#[repr(u8)]
66#[derive(Debug, PartialEq, Copy, Clone)]
67pub enum Led {
68 None = 0x0,
69 GreenOne = 0x01,
70 GreenTwo = 0x02,
71 OrangeOne = 0x04,
72 OrangeTwo = 0x08,
73 Red = 0x10,
74 All = 0x1F,
75 Other(u8),
76}
77
78impl Led {
79 fn as_u8(&self) -> u8 {
80 match self {
81 Led::None => 0x0,
82 Led::GreenOne => 0x01,
83 Led::GreenTwo => 0x02,
84 Led::OrangeOne => 0x04,
85 Led::OrangeTwo => 0x08,
86 Led::Red => 0x10,
87 Led::All => 0x1F,
88 Led::Other(val) => *val,
89 }
90 }
91}
92
93impl BitOr for Led {
94 type Output = Led;
95
96 fn bitor(self, other: Self) -> Self::Output {
97 match (self, other) {
98 (Led::None, _) => other,
99 (_, Led::None) => self,
100 _ => Led::Other(self.as_u8() | other.as_u8()),
101 }
102 }
103}
104
105static CONNECTED: AtomicBool = AtomicBool::new(false);
106
107#[derive(Debug, Clone)]
132pub struct G29 {
133 options: Options,
134 prepend_write: bool,
135 calibrated: bool,
136 inner: Arc<RwLock<InnerG29>>,
137}
138
139#[derive(Debug)]
140struct InnerG29 {
141 data: Arc<RwLock<Frame>>,
142 reader_handle: Option<thread::JoinHandle<()>>,
143 event_handlers: EventMap,
144 wheel: Option<Mutex<hidapi::HidDevice>>,
145}
146
147#[derive(Debug, PartialEq, Copy, Clone, Eq, Hash)]
167pub struct Options {
168 pub debug: bool,
169 pub range: u16,
170 pub auto_center: [u8; 2],
171 pub auto_center_enabled: bool,
172}
173
174impl Default for Options {
175 fn default() -> Self {
176 Options {
177 auto_center: [0x07, 0xff],
178 debug: false,
179 range: 900,
180 auto_center_enabled: true,
181 }
182 }
183}
184
185fn is_logitech_g29(device: &DeviceInfo) -> bool {
186 device.vendor_id() == 1133
187 && (device.product_string().unwrap() == "G29 Driving Force Racing Wheel"
188 || device.product_id() == 49743)
189 && (device.interface_number() == 0 || device.usage_page() == 1)
190}
191
192fn get_wheel_info(api: &HidApi) -> DeviceInfo {
193 let list = api.device_list();
194
195 list.into_iter()
196 .find(|device| is_logitech_g29(device))
197 .expect("No wheel found")
198 .clone()
199}
200
201impl G29 {
202 pub fn connect(options: Options) -> G29 {
206 if options.debug {
207 println!("userOptions -> {:?}", options);
208 }
209 let api = HidApi::new().expect("Failed to initialize HID API");
211
212 let wheel_info = get_wheel_info(&api);
213
214 if wheel_info.path().is_empty() {
215 if options.debug {
216 println!("findWheel -> Oops, could not find a G29 Wheel. Is it plugged in?");
217 exit(1);
218 }
219 } else if options.debug {
220 println!("findWheel -> Found G29 Wheel at {:?}", wheel_info.path());
221 }
222
223 let wheel = wheel_info.open_device(&api).expect("Failed to open device");
224 wheel
225 .set_blocking_mode(false)
226 .expect("Failed to set non-blocking mode");
227
228 let prepend_write: bool = { matches!(OS, "windows") };
229
230 let mut g29 = G29 {
231 options,
232 prepend_write,
233 calibrated: false,
234 inner: Arc::new(RwLock::new(InnerG29 {
235 wheel: Some(Mutex::new(wheel)),
236 data: Arc::new(RwLock::new([0; FRAME_SIZE])),
237 reader_handle: None,
238 event_handlers: EventMap::new(),
239 })),
240 };
241 CONNECTED.store(true, std::sync::atomic::Ordering::Release);
242
243 g29.initialize();
244
245 g29
246 }
247
248 fn initialize(&mut self) {
249 self.inner
250 .read()
251 .unwrap()
252 .wheel
253 .as_ref()
254 .unwrap()
255 .lock()
256 .unwrap()
257 .set_blocking_mode(false)
258 .expect("Failed to set non-blocking mode");
259
260 let mut data = [0u8; FRAME_SIZE];
261 let data_size = self
262 .inner
263 .read()
264 .unwrap()
265 .wheel
266 .as_ref()
267 .unwrap()
268 .lock()
269 .unwrap()
270 .read(&mut data)
271 .expect("connect -> Error reading from device.");
272
273 self.force_off(0xf3);
274
275 if data_size == FRAME_SIZE || self.calibrated {
276 if self.options.debug {
277 println!("connect -> Wheel already in high precision mode.");
278 }
279 self.listen(true);
280 } else {
281 if self.options.debug {
282 println!("connect -> Initializing Wheel.");
283 }
284
285 if !self.calibrated {
286 self.calibrate_wheel();
287 self.calibrated = true;
288 }
289
290 self.listen(false);
291 }
292 }
293
294 fn calibrate_wheel(&mut self) {
295 self.relay_os([0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00], "init_1");
297 self.relay_os([0xf8, 0x09, 0x05, 0x01, 0x01, 0x00, 0x00], "init_2");
298
299 sleep(Duration::from_secs(8));
300 }
301
302 fn listen(&mut self, ready: bool) {
303 if !ready {
304 let new_wheel = get_wheel_info(&HidApi::new().unwrap())
305 .open_device(&HidApi::new().unwrap())
306 .unwrap();
307
308 *self
309 .inner
310 .read()
311 .unwrap()
312 .wheel
313 .as_ref()
314 .unwrap()
315 .lock()
316 .unwrap() = new_wheel;
317
318 self.initialize();
319 return;
320 }
321
322 self.set_range();
323 self.set_auto_center();
324
325 if self.options.debug {
326 println!("listen -> Ready to listen for wheel events.");
327 }
328
329 let mut g29_clone = self.clone();
331 let local_self = self.inner.clone();
332 let thread_handle = thread::spawn(move || {
333 while CONNECTED.load(std::sync::atomic::Ordering::Relaxed) {
334 let mut new_data = [0u8; FRAME_SIZE];
335 match local_self
336 .read()
337 .unwrap()
338 .wheel
339 .as_ref()
340 .unwrap()
341 .lock()
342 .unwrap()
343 .read(&mut new_data)
344 {
345 Ok(size_read) if size_read == FRAME_SIZE => {
346 let local_self_write = local_self.read().unwrap();
347 let mut prev_data = local_self_write.data.write().unwrap();
348
349 if new_data == *prev_data {
350 continue;
351 }
352
353 local_self_write.event_handlers.trigger_events(
354 &prev_data,
355 &new_data,
356 &mut g29_clone,
357 );
358
359 *prev_data = new_data;
360 }
361 Ok(_) => {
362 if g29_clone.options.debug {
363 println!("listen -> Incomplete data read from device.");
364 }
365 }
366 Err(e) => {
367 if g29_clone.options.debug {
368 println!("listen -> Error reading from device: {:?}", e);
369 }
370 }
371 };
372 }
373 });
374 self.inner.write().unwrap().reader_handle = Some(thread_handle);
375 }
376
377 fn set_auto_center(&self) {
408 if self.options.auto_center_enabled {
412 self.relay_os([0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], "auto_center on");
414 self.relay_os(
415 [
416 0xfe,
417 0x0d,
418 self.options.auto_center[0],
419 self.options.auto_center[0],
420 self.options.auto_center[1],
421 0x00,
422 0x00,
423 ],
424 "set_auto_center_force",
425 );
426 } else {
427 self.relay_os(
429 [0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
430 "auto_center off",
431 );
432 }
433 }
434
435 fn set_range(&mut self) {
436 if self.options.range < 40 {
440 self.options.range = 40;
441 }
442
443 if self.options.range > 900 {
444 self.options.range = 900;
445 }
446
447 let range1 = self.options.range & 0x00ff;
448 let range2 = (self.options.range & 0xff00) >> 8;
449
450 self.relay_os(
451 [0xf8, 0x81, range1 as u8, range2 as u8, 0x00, 0x00, 0x00],
452 "set_range",
453 );
454 }
455
456 fn force_off(&self, slot: u8) {
457 self.relay_os([slot, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], "force_off");
459 }
460
461 fn relay_os(&self, data: [u8; 7], operation: &str) {
462 let mut new_data: [u8; 8] = [0; 8];
468
469 if self.prepend_write {
470 new_data = [
472 0x00, data[0], data[1], data[2], data[3], data[4], data[5], data[6],
473 ];
474 }
475
476 self.inner
477 .read()
478 .unwrap()
479 .wheel
480 .as_ref()
481 .expect("relay_os -> Wheel not found")
482 .lock()
483 .unwrap()
484 .write(if self.prepend_write { &new_data } else { &data })
485 .unwrap_or_else(|_| {
486 panic!(
487 "relay_os -> Error writing to device. Operation: {}",
488 operation
489 )
490 });
491 }
492
493 pub fn set_auto_center_force(&mut self, strength: u8, turning_multiplier: u8) {
517 self.options.auto_center = [strength, turning_multiplier];
518
519 self.set_auto_center();
520 }
521
522 pub fn set_leds(&self, leds: Led) {
545 let data = [0xf8, 0x12, leds.as_u8(), 0x00, 0x00, 0x00, 0x01];
549
550 self.relay_os(data, "set_leds");
551 }
552
553 pub fn force_friction(&self, mut left: u8, mut right: u8) {
573 if left | right == 0 {
574 self.force_off(2);
575 return;
576 }
577
578 left *= 7;
579 right *= 7;
580
581 self.relay_os(
582 [0x21, 0x02, left, 0x00, right, 0x00, 0x00],
583 "force_friction",
584 );
585 }
586
587 pub fn throttle(&self) -> u8 {
590 state::throttle(&self.inner.read().unwrap().data.read().unwrap())
591 }
592
593 pub fn brake(&self) -> u8 {
596 state::brake(&self.inner.read().unwrap().data.read().unwrap())
597 }
598
599 pub fn steering(&self) -> u8 {
602 state::steering(&self.inner.read().unwrap().data.read().unwrap())
603 }
604
605 pub fn steering_fine(&self) -> u8 {
608 state::steering_fine(&self.inner.read().unwrap().data.read().unwrap())
609 }
610
611 pub fn dpad(&self) -> DpadPosition {
619 state::dpad(&self.inner.read().unwrap().data.read().unwrap())
620 }
621
622 pub fn x_button(&self) -> bool {
624 state::x_button(&self.inner.read().unwrap().data.read().unwrap())
625 }
626
627 pub fn square_button(&self) -> bool {
629 state::square_button(&self.inner.read().unwrap().data.read().unwrap())
630 }
631
632 pub fn circle_button(&self) -> bool {
634 state::circle_button(&self.inner.read().unwrap().data.read().unwrap())
635 }
636
637 pub fn triangle_button(&self) -> bool {
639 state::triangle_button(&self.inner.read().unwrap().data.read().unwrap())
640 }
641
642 pub fn right_shifter(&self) -> bool {
644 state::right_shifter(&self.inner.read().unwrap().data.read().unwrap())
645 }
646
647 pub fn left_shifter(&self) -> bool {
649 state::left_shifter(&self.inner.read().unwrap().data.read().unwrap())
650 }
651
652 pub fn r2_button(&self) -> bool {
654 state::r2_button(&self.inner.read().unwrap().data.read().unwrap())
655 }
656
657 pub fn l2_button(&self) -> bool {
659 state::l2_button(&self.inner.read().unwrap().data.read().unwrap())
660 }
661
662 pub fn share_button(&self) -> bool {
664 state::share_button(&self.inner.read().unwrap().data.read().unwrap())
665 }
666
667 pub fn option_button(&self) -> bool {
669 state::options_button(&self.inner.read().unwrap().data.read().unwrap())
670 }
671
672 pub fn r3_button(&self) -> bool {
674 state::r3_button(&self.inner.read().unwrap().data.read().unwrap())
675 }
676
677 pub fn l3_button(&self) -> bool {
679 state::l3_button(&self.inner.read().unwrap().data.read().unwrap())
680 }
681
682 pub fn gear_selector(&self) -> GearSelector {
693 state::gear_selector(&self.inner.read().unwrap().data.read().unwrap())
694 }
695
696 pub fn plus_button(&self) -> bool {
698 state::plus_button(&self.inner.read().unwrap().data.read().unwrap())
699 }
700
701 pub fn minus_button(&self) -> bool {
703 state::minus_button(&self.inner.read().unwrap().data.read().unwrap())
704 }
705
706 pub fn spinner_right(&self) -> bool {
708 state::spinner_right(&self.inner.read().unwrap().data.read().unwrap())
709 }
710
711 pub fn spinner_left(&self) -> bool {
713 state::spinner_left(&self.inner.read().unwrap().data.read().unwrap())
714 }
715
716 pub fn spinner_button(&self) -> bool {
718 state::spinner_button(&self.inner.read().unwrap().data.read().unwrap())
719 }
720
721 pub fn playstation_button(&self) -> bool {
723 state::playstation_button(&self.inner.read().unwrap().data.read().unwrap())
724 }
725
726 pub fn clutch(&self) -> u8 {
729 state::clutch(&self.inner.read().unwrap().data.read().unwrap())
730 }
731
732 pub fn shifter_x(&self) -> u8 {
734 state::shifter_x(&self.inner.read().unwrap().data.read().unwrap())
735 }
736
737 pub fn shifter_y(&self) -> u8 {
739 state::shifter_y(&self.inner.read().unwrap().data.read().unwrap())
740 }
741
742 pub fn shifter_pressed(&self) -> bool {
744 state::shifter_pressed(&self.inner.read().unwrap().data.read().unwrap())
745 }
746
747 pub fn disconnect(&mut self) {
765 if !self.connected() {
766 return;
767 }
768
769 self.force_off(0xf3);
770 self.set_leds(Led::None);
771 self.force_friction(0, 0);
772 self.options.auto_center = [0x00, 0x00];
773 self.set_auto_center();
774
775 CONNECTED.store(false, std::sync::atomic::Ordering::Release);
778 self.inner.write().unwrap().wheel = None;
779 if let Some(handle) = self.inner.write().unwrap().reader_handle.take() {
781 handle.join().unwrap();
782 }
783 }
784
785 pub fn connected(&self) -> bool {
786 CONNECTED.load(std::sync::atomic::Ordering::Relaxed)
787 && self.inner.read().unwrap().wheel.is_some()
788 }
789
790 pub fn register_event_handler(&self, event: Event, handler: HandlerFn) -> Option<EventHandler> {
818 self.inner
819 .write()
820 .unwrap()
821 .event_handlers
822 .insert(event, handler)
823 }
824
825 pub fn unregister_event_handler(&mut self, event_handler: EventHandler) {
852 self.inner
853 .write()
854 .unwrap()
855 .event_handlers
856 .remove(event_handler);
857 }
858}