Skip to main content

cardinal_varvara/
controller_usb.rs

1#[cfg(not(feature = "uses_usb"))]
2compile_error!("controller_usb.rs should not be compiled unless the 'uses_usb' feature is enabled");
3
4#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
5use super::controller::Controller;
6#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
7use super::controller::{ControllerDevice, Key};
8#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
9use crate::Event;
10#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
11use std::any::Any;
12#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
13use uxn::Uxn;
14
15/// Only import and use ControllerGilrs if uses_gilrs feature is enabled
16#[cfg(feature = "uses_gilrs")]
17use super::controller_gilrs::ControllerGilrs;
18
19#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
20/// USB controller device for Varvara system.
21pub struct ControllerUsb {
22    /// Receiver for USB controller messages.
23    pub rx: std::sync::mpsc::Receiver<UsbControllerMessage>,
24    /// Last pedal state received from the USB device.
25    pub last_pedal: Option<u8>,
26    /// Internal controller state.
27    pub controller: Controller,
28    /// Optional chained Gilrs controller (only if uses_gilrs)
29    #[cfg(feature = "uses_gilrs")]
30    pub gilrs: Option<ControllerGilrs>,
31}
32
33#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
34impl ControllerDevice for ControllerUsb {
35    /// Sends a single character event
36    fn char(&mut self, vm: &mut Uxn, c: u8) -> Event {
37        let _event = self.controller.char(vm, c);
38        #[cfg(feature = "uses_gilrs")]
39        if let Some(gilrs) = &mut self.gilrs {
40            gilrs.char(vm, c);
41        }
42        let p = vm.dev::<crate::controller::ControllerPorts>();
43        Event {
44            vector: p.vector.get(),
45            data: Some(crate::EventData {
46                addr: crate::controller::ControllerPorts::KEY,
47                value: c,
48                clear: true,
49            }),
50        }
51        // event
52    }
53
54    /// Send the given key event, returning an event if needed
55    fn pressed(&mut self, vm: &mut Uxn, k: Key, repeat: bool) -> Option<Event> {
56        let event = self.controller.pressed(vm, k, repeat);
57        #[cfg(feature = "uses_gilrs")]
58        if let Some(gilrs) = &mut self.gilrs {
59            gilrs.pressed(vm, k, repeat);
60        }
61        event
62    }
63
64    /// Indicate that the given key has been released
65    ///
66    /// This may change our button state and return an event
67    fn released(&mut self, vm: &mut Uxn, k: Key) -> Option<Event> {
68        let event = self.controller.released(vm, k);
69        #[cfg(feature = "uses_gilrs")]
70        if let Some(gilrs) = &mut self.gilrs {
71            gilrs.released(vm, k);
72        }
73        event
74    }
75    fn as_any(&mut self) -> &mut dyn Any {
76        self
77    }
78}
79
80/// Trait for polling USB events
81pub trait ControllerPollEvents: Send {
82    /// Polls for USB events and returns a vector of events.
83    fn poll_usb_events(&mut self, vm: &mut Uxn) -> Vec<Event>;
84}
85
86#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
87impl ControllerPollEvents for ControllerUsb {
88    /// Polls for USB events and returns a vector of events.
89    fn poll_usb_events(&mut self, vm: &mut Uxn) -> Vec<Event> {
90        let mut events = Vec::new();
91
92        // Chain gilrs polling first, only if uses_gilrs
93        #[cfg(feature = "uses_gilrs")]
94        if let Some(gilrs) = &mut self.gilrs {
95            events.extend(gilrs.poll_gilrs_event(vm).into_iter().flatten());
96        }
97
98        //println!("[USB] Polling for pedal events...");
99        // Poll USB messages
100        while let Ok(msg) = self.rx.try_recv() {
101            println!("[USB] Received message: {msg:?}");
102            // VEC Footpedal: pedal state is in the first byte of the message
103            if let Some(&pedal_byte) = msg.data.first() {
104                match self.last_pedal {
105                    Some(prev) => {
106                        println!(
107                            "[USB] Pedal state changed: 0x{pedal_byte:02x} (was 0x{prev:02x})"
108                        );
109                        let changed = pedal_byte ^ prev;
110                        for i in 0..8 {
111                            let mask = 1 << i;
112                            if changed & mask != 0 {
113                                if pedal_byte & mask != 0 {
114                                    println!("[USB] Pedal {i} pressed (bit {mask:02b})");
115                                    if let Some(e) = self.controller.pressed(vm, Key::Right, true) {
116                                        events.push(e);
117                                    }
118                                    if let Some(event) = self.controller.released(vm, Key::Right) {
119                                        events.push(event);
120                                    }
121                                } else {
122                                    println!("[USB] Pedal {i} released (bit {mask:02b})");
123                                    if let Some(event) = self.controller.released(vm, Key::Right) {
124                                        events.push(event);
125                                    }
126                                }
127                            }
128                        }
129                    }
130                    None => {
131                        println!("[USB] Initial pedal state: 0x{pedal_byte:02x}");
132                    }
133                }
134                self.last_pedal = Some(pedal_byte);
135            } else {
136                println!("[USB] No pedal byte in message: {msg:?}");
137            }
138        }
139        if !events.is_empty() {
140            println!("[USB] Polling complete, returning {} events", events.len());
141        }
142        events
143    }
144    // pub fn poll_usb_events(&mut self, vm: &mut Uxn) -> Vec<Event> {
145    //     let mut events = Vec::new();
146
147    //     // Chain gilrs polling first, only if uses_gilrs
148    //     #[cfg(feature = "uses_gilrs")]
149    //     if let Some(gilrs) = &mut self.gilrs {
150    //         events.extend(gilrs.poll_gilrs_event(vm).into_iter().flatten());
151    //     }
152    //     events
153    // }
154}
155
156#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
157impl ControllerUsb {
158    /// Helper to construct a ControllerUsb with optional gilrs chaining.
159    #[cfg(feature = "uses_gilrs")]
160    pub fn new(
161        controller: Controller,
162        rx: std::sync::mpsc::Receiver<UsbControllerMessage>,
163        gilrs: Option<ControllerGilrs>,
164    ) -> Self {
165        ControllerUsb {
166            rx,
167            last_pedal: None,
168            controller,
169            gilrs,
170        }
171    }
172
173    #[cfg(not(feature = "uses_gilrs"))]
174    pub fn new(
175        controller: Controller,
176        rx: std::sync::mpsc::Receiver<UsbControllerMessage>,
177    ) -> Self {
178        ControllerUsb {
179            rx,
180            last_pedal: None,
181            controller,
182        }
183    }
184
185    #[allow(dead_code)]
186    /// Checks the current button states and returns an event if any button state changed.
187    fn check_buttons(&mut self, vm: &mut Uxn, repeat: bool) -> Option<Event> {
188        self.controller.check_buttons(vm, repeat)
189    }
190}
191
192#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
193use hidapi::HidApi;
194use std::sync::mpsc;
195use std::thread;
196
197#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
198/// Message from USB controller thread
199#[derive(Debug)]
200pub struct UsbControllerMessage {
201    /// Raw data received from the USB device.
202    pub data: Vec<u8>,
203}
204
205#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
206/// USB device configuration for controller
207#[derive(Clone, Copy, Debug)]
208pub struct UsbDeviceConfig {
209    /// USB vendor ID
210    pub vendor_id: u16,
211    /// USB product ID
212    pub product_id: u16,
213}
214
215#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
216impl Default for UsbDeviceConfig {
217    /// Default to VEC Footpedal: idVendor = 0x05f3, idProduct = 0x00ff
218    fn default() -> Self {
219        // Default to VEC Footpedal: idVendor = 0x05f3, idProduct = 0x00ff
220        // Alternative: Microsoft device: idVendor = 0x045e, idProduct = 0x0b13
221        // Change which is returned by commenting/uncommenting as needed
222
223        // VEC Footpedal (default)
224        // UsbDeviceConfig {
225        //     vendor_id: 0x05f3,
226        //     product_id: 0x00ff,
227        // }
228
229        // Microsoft device (alternative)
230        // UsbDeviceConfig {
231        //     vendor_id: 0x045e,
232        //     product_id: 0x0b13,
233        // }
234
235        // By default, return VEC Footpedal
236        UsbDeviceConfig {
237            vendor_id: 0x05f3,
238            product_id: 0x00ff,
239        }
240    }
241}
242
243#[cfg(all(feature = "uses_usb", not(target_arch = "wasm32")))]
244/// Spawns a background thread to read from a HID device and sends data over a channel
245pub fn spawn_usb_controller_thread(
246    config: UsbDeviceConfig,
247) -> mpsc::Receiver<UsbControllerMessage> {
248    let (tx, rx) = mpsc::channel();
249    thread::spawn(move || {
250        println!("[USB] Starting HID thread, attempting to create API instance...");
251        let api = match HidApi::new() {
252            Ok(api) => api,
253            Err(e) => {
254                println!("[USB] Failed to create HID API instance: {e}");
255                return;
256            }
257        };
258        println!(
259            "[USB] HID API instance created. Attempting to open device {:04x}:{:04x}...",
260            config.vendor_id, config.product_id
261        );
262        let joystick = match api.open(config.vendor_id, config.product_id) {
263            Ok(dev) => {
264                println!("[USB] Device opened successfully.");
265                dev
266            }
267            Err(e) => {
268                println!("[USB] Failed to open device: {e}");
269                return;
270            }
271        };
272        loop {
273            let mut buf = [0u8; 256];
274            match joystick.read(&mut buf[..]) {
275                Ok(res) => {
276                    let data = buf[..res].to_vec();
277                    println!("[USB] Read {res} bytes: {data:?}");
278                    let _ = tx.send(UsbControllerMessage { data });
279                }
280                Err(e) => {
281                    println!("[USB] Error reading from device: {e}");
282                }
283            }
284        }
285    });
286    rx
287}