From 6ba86985d52b3fd579185158419d1272f8c465d0 Mon Sep 17 00:00:00 2001 From: Naxdy Date: Mon, 11 Mar 2024 17:17:40 +0100 Subject: [PATCH] implement rudimentary button handling, prepare SPI --- flake.nix | 2 +- src/gcc_hid.rs | 73 +++++++++++++++++++++-- src/input.rs | 113 +++++++++++++++++++++++++++++++++++ src/main.rs | 158 ++++++++++++++++++++++++++----------------------- 4 files changed, 265 insertions(+), 81 deletions(-) create mode 100644 src/input.rs diff --git a/flake.nix b/flake.nix index 460486e..d815d63 100644 --- a/flake.nix +++ b/flake.nix @@ -83,7 +83,7 @@ devShells.default = pkgs.mkShell { nativeBuildInputs = builtins.attrValues { inherit rustToolchain; - inherit (pkgs) gcc-arm-embedded flip-link elf2uf2-rs picotool probe-rs; + inherit (pkgs) gcc-arm-embedded flip-link elf2uf2-rs picotool probe-rs cargo-expand; }; CARGO_TARGET_THUMBV6M_NONE_EABI_RUNNER = "probe-rs run --chip RP2040 --protocol swd"; diff --git a/src/gcc_hid.rs b/src/gcc_hid.rs index d21f74b..4162072 100644 --- a/src/gcc_hid.rs +++ b/src/gcc_hid.rs @@ -1,8 +1,14 @@ use core::default::Default; -use defmt::{error, info, unwrap}; -use packed_struct::{derive::PackedStruct, prelude::packed_bits, types::Integer, PackedStruct}; -use usb_device::bus::{UsbBus, UsbBusAllocator}; +use defmt::{error, info, unwrap, Debug2Format}; +use embedded_hal::timer::CountDown as _; +use fugit::ExtU32; +use packed_struct::{derive::PackedStruct, PackedStruct}; +use rp2040_hal::timer::CountDown; +use usb_device::{ + bus::{UsbBus, UsbBusAllocator}, + device::{UsbDeviceBuilder, UsbVidPid}, +}; use usbd_human_interface_device::{ descriptor::InterfaceProtocol, device::DeviceClass, @@ -10,10 +16,11 @@ use usbd_human_interface_device::{ InBytes64, Interface, InterfaceBuilder, InterfaceConfig, OutBytes64, ReportSingle, UsbAllocatable, }, + usb_class::UsbHidClassBuilder, UsbHidError, }; -use fugit::ExtU32; +use crate::input::GCC_STATE; #[rustfmt::skip] pub const GCC_REPORT_DESCRIPTOR: &[u8] = &[ @@ -105,7 +112,7 @@ pub struct Buttons2 { #[packed_field(bits = "3")] pub button_l: bool, #[packed_field(bits = "4..=7")] - pub blank1: Integer>, + pub blank1: u8, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct)] @@ -236,3 +243,59 @@ fn get_gcinput_hid_report(input_state: &GcReport) -> [u8; 37] { buffer } + +pub fn usb_transfer_loop<'a, T: UsbBus>( + usb_bus: UsbBusAllocator, + mut poll_timer: CountDown<'a>, +) -> ! { + info!("Got to this point"); + let mut gcc = UsbHidClassBuilder::new() + .add_device(GcConfig::default()) + .build(&usb_bus); + + info!("Got the gc"); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x057e, 0x0337)) + .manufacturer("Naxdy") + .product("NaxGCC") + .serial_number("fleeb") // TODO: Get this from the flash unique id + .device_class(0) + .device_protocol(0) + .device_sub_class(0) + .self_powered(false) + .max_power(500) + .max_packet_size_0(64) + .build(); + + poll_timer.start(1.millis()); + + info!("Got here"); + + loop { + if poll_timer.wait().is_ok() { + match gcc.device().write_report(&(unsafe { GCC_STATE })) { + Err(UsbHidError::WouldBlock) => {} + Ok(_) => {} + Err(e) => { + error!("Error: {:?}", Debug2Format(&e)); + panic!(); + } + } + } + if usb_dev.poll(&mut [&mut gcc]) { + match gcc.device().read_report() { + Err(UsbHidError::WouldBlock) => {} + Err(e) => { + error!("Failed to read report: {:?}", Debug2Format(&e)); + } + Ok(report) => { + info!("Received report: {:08x}", report.packet); + // rumble packet + if report.packet[0] == 0x11 { + info!("Received rumble info: Controller1 ({:08x}) Controller2 ({:08x}) Controller3 ({:08x}) Controller4 ({:08x})", report.packet[1], report.packet[2], report.packet[3], report.packet[4]); + } + } + } + } + } +} diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..6f4488d --- /dev/null +++ b/src/input.rs @@ -0,0 +1,113 @@ +use embedded_hal::digital::{v2::InputPin, v2::IoPin}; +use rp2040_hal::gpio::{FunctionSpi, Pin, PinId, PullDown}; + +use crate::gcc_hid::{Buttons1, Buttons2, GcReport}; + +pub static mut GCC_STATE: GcReport = GcReport { + buttons_1: Buttons1 { + button_a: false, + button_b: false, + button_x: false, + button_y: false, + dpad_left: false, + dpad_right: false, + dpad_down: false, + dpad_up: false, + }, + buttons_2: Buttons2 { + button_start: false, + button_z: false, + button_r: false, + button_l: false, + blank1: 0, + }, + stick_x: 0, + stick_y: 0, + cstick_x: 0, + cstick_y: 0, + trigger_l: 0, + trigger_r: 0, +}; + +macro_rules! pin_inputs { + ($x:tt {$($f:tt: $g:tt),*}) => { + pub struct $x<$($g,)*> + where + $( + $g: InputPin, + )* + { + $( + pub $f: $g, + )* + } + }; +} + +macro_rules! assign_pins { + ($gcc:expr, $inputs:tt, {$($p:tt.$c:tt),*}) => { + $( + $gcc.$p.$c = $inputs.$c.is_low().map_err(|_| "").unwrap(); + )* + }; +} + +pin_inputs!(BasicInputs { + button_a: A, + button_b: B, + button_x: X, + button_y: Y, + dpad_left: Dl, + dpad_right: Dr, + dpad_down: Dd, + dpad_up: Du, + button_start: S, + button_z: Z, + button_r: R, + button_l: L +}); + +pub fn input_loop< + A: InputPin, + B: InputPin, + X: InputPin, + Y: InputPin, + Dl: InputPin, + Dr: InputPin, + Dd: InputPin, + Du: InputPin, + S: InputPin, + Z: InputPin, + R: InputPin, + L: InputPin, +>( + basic_inputs: BasicInputs, +) -> ! { + let update_gcc_state = || unsafe { + // simple booleans + assign_pins!(GCC_STATE, basic_inputs, { + buttons_1.button_a, + buttons_1.button_b, + buttons_1.button_x, + buttons_1.button_y, + buttons_1.dpad_left, + buttons_1.dpad_right, + buttons_1.dpad_down, + buttons_1.dpad_up, + buttons_2.button_start, + buttons_2.button_z, + buttons_2.button_r, + buttons_2.button_l + }); + + // TODO: sticks + GCC_STATE.cstick_x = 127; + GCC_STATE.cstick_y = 127; + GCC_STATE.stick_x = 127; + GCC_STATE.stick_y = 127; + }; + + loop { + update_gcc_state(); + } +} diff --git a/src/main.rs b/src/main.rs index 53a34d5..4f5b29f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,17 +10,16 @@ #![no_main] mod flash_mem; mod gcc_hid; +mod input; -use core::fmt::Write; -use defmt::{error, info, Debug2Format}; -use gcc_hid::{GcConfig, GcReport}; +use defmt::{error, info}; +use gcc_hid::GcConfig; -use fugit::ExtU32; +use fugit::{ExtU32, RateExtU32}; // Ensure we halt the program on panic (if we don't mention this crate it won't // be linked) use defmt_rtt as _; -use packed_struct::PackedStruct; use panic_halt as _; // Alias for our HAL crate @@ -29,25 +28,32 @@ use rp2040_hal as hal; // A shorter alias for the Peripheral Access Crate, which provides low-level // register access use hal::{ - gpio::FunctionUart, - pac, - uart::{UartConfig, UartPeripheral}, + gpio::FunctionSpi, + multicore::{Multicore, Stack}, + pac, Spi, }; // Some traits we need use embedded_hal::{ - blocking::delay::DelayMs, - digital::v2::{InputPin, OutputPin}, + blocking::spi::Transfer, + digital::v2::OutputPin, + spi::{FullDuplex, MODE_0}, timer::CountDown, }; -use rp2040_hal::Clock; + use usb_device::{ bus::UsbBusAllocator, - device::{UsbDeviceBuilder, UsbDeviceState, UsbVidPid}, + device::{UsbDeviceBuilder, UsbVidPid}, }; -use usbd_human_interface_device::{usb_class::UsbHidClassBuilder, UsbHidError}; +use usbd_human_interface_device::usb_class::UsbHidClassBuilder; -use crate::flash_mem::{read_from_flash, write_to_flash}; +use crate::{ + flash_mem::{read_from_flash, write_to_flash}, + gcc_hid::usb_transfer_loop, + input::{input_loop, BasicInputs}, +}; + +static mut CORE1_STACK: Stack<4096> = Stack::new(); /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -89,13 +95,10 @@ fn main() -> ! { .ok() .unwrap(); - let mut timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); - - let mut poll_timer = timer.count_down(); - poll_timer.start(1.millis()); + let timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); // The single-cycle I/O block controls our GPIO pins - let sio = hal::Sio::new(pac.SIO); + let mut sio = hal::Sio::new(pac.SIO); // Set the pins to their default state let pins = hal::gpio::Pins::new( @@ -105,8 +108,6 @@ fn main() -> ! { &mut pac.RESETS, ); - let mut gcc_state = GcReport::default(); - // usb parts let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, @@ -116,30 +117,6 @@ fn main() -> ! { &mut pac.RESETS, )); - let mut gcc = UsbHidClassBuilder::new() - .add_device(GcConfig::default()) - .build(&usb_bus); - - let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x057e, 0x0337)) - .manufacturer("Naxdy") - .product("NaxGCC") - .serial_number("fleeb") - .device_class(0) - .device_protocol(0) - .device_sub_class(0) - .self_powered(false) - .max_power(500) - .max_packet_size_0(64) - .build(); - - gcc_state.stick_x = 0; - gcc_state.stick_y = 0; - gcc_state.trigger_l = 21; - gcc_state.cstick_x = 127; - gcc_state.cstick_y = 127; - - let btn_pin = pins.gpio15.into_pull_up_input(); - unsafe { let some_byte: u8 = 0xAB; info!("Byte to be written is {:02X}", some_byte); @@ -148,38 +125,69 @@ fn main() -> ! { info!("Byte read from flash is {:02X}", r); } + let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); + let cores = mc.cores(); + let core1 = &mut cores[1]; + + let _transfer_loop = core1 + .spawn(unsafe { &mut CORE1_STACK.mem }, move || { + let mut poll_timer = timer.count_down(); + poll_timer.start(1.millis()); + + usb_transfer_loop(usb_bus, poll_timer) + }) + .unwrap(); + info!("Initialized"); - // Configure GPIO25 as an output - let mut led_pin = pins.gpio25.into_push_pull_output(); - loop { - if poll_timer.wait().is_ok() { - match gcc.device().write_report(&gcc_state) { - Err(UsbHidError::WouldBlock) => {} - Ok(_) => {} - Err(e) => { - led_pin.set_high().unwrap(); - error!("Error: {:?}", Debug2Format(&e)); - panic!(); - } - } - } - if usb_dev.poll(&mut [&mut gcc]) { - match gcc.device().read_report() { - Err(UsbHidError::WouldBlock) => {} - Err(e) => { - error!("Failed to read report: {:?}", Debug2Format(&e)); - } - Ok(report) => { - info!("Received report: {:08x}", report.packet); - // rumble packet - if report.packet[0] == 0x11 { - info!("Received rumble info: Controller1 ({:08x}) Controller2 ({:08x}) Controller3 ({:08x}) Controller4 ({:08x})", report.packet[1], report.packet[2], report.packet[3], report.packet[4]); - } - } - } - } + let mut ccs = pins.gpio23.into_push_pull_output(); + let mut acs = pins.gpio24.into_push_pull_output(); - gcc_state.buttons_2.button_z = btn_pin.is_low().unwrap(); + ccs.set_low(); + acs.set_low(); + + let spi_device = pac.SPI0; + + let clk = pins.gpio6.into_function::(); + let tx = pins.gpio7.into_function::(); + let rx = pins.gpio4.into_function::(); + + let spi_pin_layout = (tx, rx, clk); + + let mut spi = Spi::<_, _, _, 8>::new(spi_device, spi_pin_layout).init( + &mut pac.RESETS, + 3_000_000u32.Hz(), + 3_000_000u32.Hz(), + MODE_0, + ); + + let mut w = [0b11010000u8; 3]; + + info!("W is {}", w); + + let r = spi.transfer(&mut w); + + match r { + Ok(t) => { + info!("T is {}", t) + } + Err(e) => { + error!("SPI transfer failed: {}", e); + } } + + input_loop(BasicInputs { + button_a: pins.gpio17.into_pull_up_input(), + button_b: pins.gpio16.into_pull_up_input(), + button_x: pins.gpio18.into_pull_up_input(), + button_y: pins.gpio19.into_pull_up_input(), + button_z: pins.gpio20.into_pull_up_input(), + button_r: pins.gpio21.into_pull_up_input(), + button_l: pins.gpio22.into_pull_up_input(), + dpad_left: pins.gpio8.into_pull_up_input(), + dpad_up: pins.gpio9.into_pull_up_input(), + dpad_down: pins.gpio10.into_pull_up_input(), + dpad_right: pins.gpio11.into_pull_up_input(), + button_start: pins.gpio5.into_pull_up_input(), + }); }