milador / RaspberryPi-Joystick

A virtual HID USB joystick created using Raspberry Pi
MIT License
114 stars 29 forks source link

Emulate a Nintendo Switch controller #6

Open gdsports opened 3 years ago

gdsports commented 3 years ago

NSGamepad configures the gadget device into a USB gamepad. With the help of a Mayflash Magic NS adapter (about $20), the Pi Zero gamepad can control a Nintendo Switch. See PR https://github.com/milador/RaspberryPi-Joystick/pull/5

milador commented 3 years ago

@gdsports Awesome work. I will add a separate readme for it.

gdsports commented 3 years ago

I pushed up an example of using gpio pins to trigger gamepad buttons. The SDA/SCL and UART pins are not used because they might be useful for interfacing to other devices.

milador commented 3 years ago

Awesome. I don't have have Nintendo switch to test this but looks great. I try to get someone to test it. Thanks

milador commented 3 years ago

I tried the same descriptor which I used in a 32bit MCU that worked with XAC and still it doesn't work.

gdsports commented 3 years ago

I have had no success connecting to an XAC with the Pi Zero dwc2/libcomposite. I suspect kernel driver changes will be required to make this work but I am not a Linux driver guru.

Another option is to connect a small SAMD21 board (for example, QT Py or Seeeduino XIAO) programmed as an XAC compatible joystick via Pi UART. This frees up the Zero USB OTG port so it can be used in USB host mode. This option can also support two such boards, one for each XAC USB port. I will add a UART interface option to this project.

https://github.com/gdsports/xac_joystick_tinyusb

It should be possible to use Pi Pico boards instead of SAMD21 boards but Pi Picos are hard to get. I will probably take a look at Pi Pico when I have some time.

milador commented 3 years ago

I will get my Pi Picos by next week. I have got it working with ItsyBitsy board which has M0 chip. But having two different MCUs make the design hard to maintain and more difficult for XAC users to put it together. I was looking for some way to convert Bluetooth hid mouse to hid joystick for XAC. The Arduino nano RP2040 would work if we get Pico working.

milador commented 3 years ago

Great work though. I will use it for future projects. As I am switching to QT for most projects. Would be great if we can have it working with Pico soon as well.

gdsports commented 3 years ago

Adafruit nRF52840 boards work with the xac tinyusb driver but BT Classic is not supported. My BT keyboard and mouse are BT Classic so they do not work with the nRF52840. I was able to get an nRF52840 to send BLE HID keystrokes to another nRF52840 in BLE HID central mode. This probably works for BLE mice although I am not sure if this useful. Adafruit includes an Arduino example for BLE HID central but it only does keyboard. It has hooks for BLE HID mouse but it is not fully implemented. I will take a look at this.

My Pi Picos should arrive next week.

milador commented 3 years ago

I actually only need Bluetooth mouse working and keyboard not necessarily but that would be even better. Let me know if you have the sample code to test. That would solve my problem. I got it working with Teensy 3.6 but it's expensive comparing to your suggestion with nRF52840 and needs separate Bluetooth dongle. I have nRF52840 dongle which I can test your suggestion.

milador commented 3 years ago

@gdsports Would Adafruit ItsyBitsy nRF52840 Express work with this as well or do I need to modify the uf2?

gdsports commented 3 years ago

@milador I was never able to program an nRF52840 by dragging and dropping a UF2 file. I had to compile and upload using the IDE. This seems to only work with SAMD boards at the moment.

gdsports commented 3 years ago

The latest PR named xac_fix makes USB HID gadget work with the XAC! I was not making any progress with the nRF52840 so I switch gears to pi zero w. I changed a kernel source code but this does not require replacing the entire kernel or building a new IMG file. Replacing a single file installs the updated USB HID gadget driver (usb_f_hid.ko). A reboot is a good idea make sure the new version is running.

On the nRF52840 I cannot even get key input in Central mode. I recall this worked a while back but it does not work now.

The Zero is a better solution since it works for BT Classic and BLE. The Raspberry Pi OS BT GUI tool is not helpful. It does not auto connect to BT devices so the user must use the tray applet to connect to devices on every boot and disconnect. :{

milador commented 3 years ago

This is awesome 👌 I will give it a try tomorrow with few input devices and hopefully write a detailed instructions for it. It should be possible to use a little LCD and buttons on pi to scan and connect to the device. I have done something very similar to that so I will add it as alternative option in instructions. I might do a short video of raspberry solution and teensy solution for the community of XAC users to show the potentials. This opens the door for lots of possibilities.

gdsports commented 3 years ago

I am happy to hear you have a better way to configure BT. Running the GUI+VNC slows down the Pi Zero boot up so it is best not to avoid them.

milador commented 3 years ago

I tried your changes and I think it doesn't work since I am using older kernel version. I updated it to 5.10 but still no luck. So just put new fresh image and about to do another test. I make a separate page for it once I get it working. Some people may want to use simple 8 button joystick. Yes, VNC slows down and a simple Interface would work. I did a arduino .hex uploader using RPi zero and Ardafruit lcd module. I just need to combine that with my device scanner code.Thanks again for your support.

gdsports commented 3 years ago

I have been testing with the latest kernel. I will make sure it works starting from a fresh installation.

gdsports commented 3 years ago

I burned 2021-01-11-raspios-buster-armhf.zip to a microsd card to make sure I have not left out any steps or files.

Boot PiZeroW then use raspi-config to enable and configure WiFi, ssh, VNC (remote desktop). Change hostname to btgadget.

Update to the latest kernel and install required and optional packages.

sudo apt update
sudo apt full-upgrade
sudo apt install git python3-evdev python3-gpiozero
sudo apt install vim ctags screen build-essential # optional stuff I use
sudo reboot

Login again. Verify the kernel version.

uname -a
Linux btgadget 5.10.11+ #1399 Thu Jan 28 12:02:28 GMT 2021 armv6l GNU/Linux

Pair BT keyboard/mouse using GUI.

Set up USB gadget mode.

git clone https://github.com/milador/RaspberryPi-Joystick
cd RaspberryPi-Joystick
sudo echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
sudo echo "dwc2" | sudo tee -a /etc/modules
sudo echo "libcomposite" | sudo tee -a /etc/modules
KERNEL_RELEASE=`uname -r`
sudo cp /lib/modules/${KERNEL_RELEASE}/kernel/drivers/usb/gadget/function/usb_f_hid.ko /lib/modules/${KERNEL_RELEASE}/kernel/drivers/usb/gadget/function/usb_f_hid.ko.orig
sudo cp rpi-5.10/usb_f_hid.ko /lib/modules/${KERNEL_RELEASE}/kernel/drivers/usb/gadget/function/
sudo reboot

Login again.

cd RaspberryPi-Joystick/8_Buttons_Joystick
sudo ./8_buttons_joystick
cd Code
sudo python3 joystick_demo.py

This is my test setup.

Pi4 - XAC - PiZeroW
       |
      5V2A

On the Pi4, jstest-gtk (sudo apt install jstest-gtk) is running which shows the Xbox Controller buttons and axes. The joystick demo program running on the PiZeroW should be pressing and releasing buttons and moving the (X,Y) axes.

If the XAC does not its own power suppy, it may not be able to supply enough current to the PiZeroW. I am sure the PiZeroW draws far more than 100 mA but less than 500 mA. When the XAC has its power supply, it can supply as much as 500 mA to each of its USB host ports.

milador commented 3 years ago

Tested and it's working. My PC decided to do a BIOS update during this time and messed up everything! Checked it with another PC and all good. I will just update the instructions now. Thanks for sending me your details commands.

milador commented 3 years ago

@gdsports Added x and y mapping for mice to joystick using 2 modes. One will keep the output position and the other mode returns to center when you stop moving mice. The Scroll wheel is next. I am turning it to a button press that keep pressing when Scroll up and release button when you scroll down. Take a look and see if there are bugs anywhere. I powered RPI zero using external power source and that is working as well without connecting power source to XAC.

gdsports commented 3 years ago

My first Pi Pico driver using the C SDK. Bare minimum example but it works on an XAC.

https://github.com/gdsports/xac_joystick_pipico

I'll take a look at your latest code. Looks like lots of progress.

milador commented 3 years ago

Awesome 👌 I will try it when I get my pico. I am still waiting. I also working on running the mouse and keyboard automatically using systemctl. Doesn't start no matter what I do but should be able to figure out the issue by printing few logs.

milador commented 3 years ago

@gdsports It seems that /etc/udev/rules.d is the solution.

gdsports commented 3 years ago

@milador I am back! I had some urgent work so I had to pause. I saw the youtube videos and it is gratifying to see the system in use with a game.

Running the python program as a service makes sense. As does using a udev rule to make the hidg0 accessible without being root.

I have never tried USB gadget on a Pi4 so I will give it a try. I am concerned it draws too much current so I hope the PC/laptop protects itself from this. A disadvantage of the PiZ is the quantity 1 limit so the Pi4 is a good alternative.

milador commented 3 years ago

@gdsports Glad you are back! Appreciate your support and I already made some contacts to test it with few different devices.

I just tested a bluetooth switch interface and it worked other than pairing issue. It seems debian bluetooth GUI interface doesn't support authentication so I need to create a helper software or python code to take care of that. Mapping profile would be another feature of helper software.

I found mice is not the best option as joystick as you need to keep moving the mice. I am wondering if move and lock direction until you move it again would be a better option.

Looked at ways to create a modified OS with all the code pre installed and it would be way to go once the code is tested and working with few different devices.

I will post another video tomorrow testing another device.

milador commented 3 years ago

@gdsports I am having issues with NS version after making changes to kernel module. All 4 other descriptors work but NS descriptor doesn't get recognized any more. Can you test it again? Probably need to go back to original hid kernel modules.

BTW, did you use toolchain for a 64-bit kernel or 32-bit for compiling on rpi4? I compiled it but doesn't work with current setting. The ones you pushed work.

gdsports commented 3 years ago

I used the 32-bit toolchain for all. I have not tried the NS version in a while so I will take a look. This is what I use.

KERNEL=kernel7l
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
make -j ${NUMCPU} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
DESTDIR="${DEST}/5.10.11-v7l+/${TAIL}"
if [ ! -d ${DESTDIR} ]
then
    mkdir -p ${DESTDIR}
fi
find . -name usb_f_hid.ko -print0 |xargs -0 -I{} cp {} "${DESTDIR}"
gdsports commented 3 years ago

@milador And I build from a branch and commit as close as possible to the current kernel. I should have all the steps in the Drivers/README.md but let me know if I left things out.

git clone --depth=1 --branch rpi-5.10.y https://github.com/raspberrypi/linux
cd linux
git checkout raspberrypi-kernel_1.20210201-1
milador commented 3 years ago

@gdsports I did all the steps other than checkout. I repeat it again maybe I messed up with changes to hid descriptor.

milador commented 3 years ago

@gdsports I get: error: pathspec 'raspberrypi-kernel_1.20210201-1' did not match any file(s) known to git

when I do checkout.

milador commented 3 years ago

@gdsports It's working now. It was a permission issue.

gdsports commented 3 years ago

OK, glad to hear it worked out. I found a USB Y cable and powered hub work on a Switch in its docking station USB host ports. In brief, a PiZW does not need either one. It works fine from one USB host port.

A Pi4B or Pi400 (draws about 100 mA more than 4B) works with either the Y cable or powered hub. If USB devices are plugged into the 4b/400 USB hosts ports, the powered hub is a better option. I noticed on Tindie we are not the only ones using USB gadget on 4B/400. There are at least two USB power-data splitters. The splitter advantage over a powered hub is a standard 4B power supply can supply up to 3A.

https://www.tindie.com/products/8086net/usbpwr-splitter/

https://www.tindie.com/products/8086net/5v-usb-c-dual-supply-dual-ideal-diodes/

A Logitech Extreme 3D flightstick works when plugged into a 4B USB host port. evdev can decode all axes and buttons so they can be mapped to gamepad buttons and axes. The stick can be used for 2 stick games because it has an 8 way hat switch on top which can be mapped to the right gamepad stick.

A DS4 (playstation dual shock 4) also works on a 4B USB host port. This means it can be used by a co-pilot. The Switch console does not have a co-pilot mode so it can be done by the 4B.

gdsports commented 3 years ago

@milador ESP32-S3 will have BT Classic, BLE, and mesh plus USB OTG. Not powerful enough to run Linux but more than enough for BT mouse to USB joystick. The video says it still months away from production. The first ESP32 with USB OTG, the ESP32-S2, does not have BT.

https://www.youtube.com/watch?v=kQnkE04I2mQ

milador commented 3 years ago

@gdsports Thank you again for putting time on this project.

I will make a tested devices list with all devices tested so far. We don't need to test every mice or keyboard but those that we think have unique features like the one you tested.

I finished designing 2 custom PCB switch HATs for RPi zero, 4 and Pico with 3.5 jacks. Is there any other feature you think I should add? LED or USB spliter as well? Not sure if there is a way to get USB data pins to the HAT but will look into it. That would make everything in one package.

I read that you can run a version of Linux in RPI pico. So I can just add the USB spliter to HAT and we are set. I can send you the PCB once I test it or I send you the files if you want to get yours.

ESP32-S3 would be great option. I made the wifi joystick converter using S2 but there is at least 1s lag which makes it not suitable for gaming.Glad the BT is back on S3.This is great as it will be way cheaper and easier to run being low power device.

Have you tried CH559 MCU? A bit tricky to program but very cheap and has 2 USB host. I got 2 dev boards for it but can't get the compiler working.

gdsports commented 3 years ago

@milador CH559 MCU is very interesting since it can replace a Teensy 3.6 with a slower CPU but much cheaper. I do not think I will find time to try it. The software support appears very weak.

I am interested in seeing the switch HATs but this is not urgent. So the HATs would make the Pi have AT switch jacks for gamepad buttons like the XAC? Sound very good! I am interested in the files but do not need boards at the moment. I do not need too much distractions. I will attempt to stick mostly to USB software.

I do not see how to do the USB power data splitter on the HAT but it would be nice.

milador commented 3 years ago

@gdsports No worries. Yes , It will be like XAC. Maybe I send you the assembled one in few months just to have it and see result of your contribution in action :) We can discuss that later and you can always watch the video of it if you think that's better.

One idea would be to add the splitter to PCB similar to those you found on Tindie. So the user will still need the USB cables but it all will be in one HAT instead of having the splitter hanging outside.

I will go over your changes in few minutes. Great work as usual.

milador commented 3 years ago

NSGamepad is working on PC for me now after your changes. So there are 14 bits for buttons, 2 bytes for x and y axis, how many bytes for dpad and hat? @gdsports

milador commented 2 years ago

@gdsports I am going to complete the script you put together and update the instructions