Comments (210)
I'd love to see an iOS API for the JoyCon via Bluetooth.
UPDATE: iOS uses its own Bluetooth controller specification which means it does not work natively with the Joy-Con or Switch Pro controllers.
from nintendo_switch_reverse_engineering.
does anybody know if it would be emulate a joycon / pro controller using a raspberry pi zero in gadget mode?
either that or using as pi 3 over bluetooth?
from nintendo_switch_reverse_engineering.
Over USB the pro controller just does a handshake, then switches to bluetooth.
Descriptor:
procontroller descriptor.txt
Beagle analyzer trace:
data-center-windows-x86_64-v6.72.zip
from nintendo_switch_reverse_engineering.
I've bought an Ubertooth One, and with some scanning I've managed to get the device "Nintendo Switch" to show up with an associated BTADDR, hopefully I'll make some more progress later today when I get the chance, progress might be a bit slow as I familiarize myself with the Ubertooth One. If anyone wants me to run any tests or needs any specific info, just let me know.
Also, can anyone @shinyquagsire23 @riking confirm whether or not the JoyCons w/charging grip or pro controller communicate over USB when connected to the dock (or do they just charge)? They are clearly capable, so I wouldn't be surprised if they do; If they do, it should be relatively easy to sniff/intercept and it could provide some insight on the bluetooth JoyCon <-> Switch communication.
from nintendo_switch_reverse_engineering.
@aspalmer Since 3.0 supports Pro Controller 100% wired, I'm curious if you'd be able to do another USB MITM to see what it requests. I have the protocol down but I can't say I'm not curious whether about I missed something or not.
from nintendo_switch_reverse_engineering.
Is it possible to have a small guide on how to use joycon spoof ?
I want to be able to simulate a sequence of buttons on Linux for a project. (With Raspberry Zero W with built-in Bluetooth)
from nintendo_switch_reverse_engineering.
Hey all, Im new to the thread and the "scene" in general. I got here because I am trying to connect to the nintendo switch console via bluetooth in order make a "3rd party" controller.
It seems that most of the bluetooth development has gone towards connecting to the joycon itself, rather than the console. So maybe I could even offer up some new information.
I am using an stm32f2 series chip and a CC2564 bluetooth module. I have more or less exactly copied the SDP record of a left joycon controller into my device, and set up everything as much the "same" as possible.
The switch appears to connect to my device, pass it a link key, request encryption and then connect sucessfully. However, nothing appears on the console's pairing screen. As you know usually thre is a notification that says "paired".
This is probably to be expected, since I am not sending it any data yet.
If I try to send an 0x21 report (which works fine with the Windows joycon driver you awsome people wrote), nothing happens.
The console appears to be sending me periodic messages. These are the messages
HID Data Indication, ReportType: rtOutput, ReportLength: 49,
Report: 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 <all zero to end>
Report: 0x01 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 <all zero to end>
Report: 0x01 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 <all zero to end>
I assume I would have to reply to this message to get fully detected by the console. I am doing further research now, but does anyone already know offhand what the chances of sucessfully pairing up with the switch console are, and what I should do next. Hopefully this is just a simple eeprom read or something, rather than something cryptographic. I know the PS4 controller must respond to periodic cryptographic challenges to stay connected over bluetooth... My fingers are crossed.
from nintendo_switch_reverse_engineering.
thanks, I did figure out the accelerometer and gyroscope data in the joycon status packet today, but only in the physical connection bewteen the joycon and console. I haven't began working on the bluetooth level yet, but I'll keep it in mind when I do.
from nintendo_switch_reverse_engineering.
Checked out the USB capture from @aspalmer and sending 0x80 0x01 gives me that MAC packet. It seems to respond to some of the other output reports in the capture similarly, so it seems that two Joy-Con in a charging grip effectively functions as a Pro Controller with two interfaces.
from nintendo_switch_reverse_engineering.
@riking I figured out what stick_unknown is
it appears that the X component of the stick data isn't just nibble reversed, specifically, the second nibble of second byte is combined with the first nibble of the first byte to get the correct X stick value:
uint8_t stick_horizontal = ((stick_data[1] & 0x0F) << 4) | ((stick_data[0] & 0xF0) >> 4);
I don't have any idea what the other nibbles are, they seem random to me, but I haven't looked at them too closely.
from nintendo_switch_reverse_engineering.
I made a custom board for remotely controlling joycons https://github.com/dekuNukem/joyAnalog
You can take apart a pair of joycons, solder wires on to button test points and connect them to the board. It's a lot of work but before the joycon is completely reverse engineered this is probably the only way. Here s a video: https://www.youtube.com/watch?v=aj1JLARaZQg
from nintendo_switch_reverse_engineering.
@popeter45 Should be doable using GadgetFS/FunctionFS since you can define your USB descriptors, though I dunno if they speak HID directly.
from nintendo_switch_reverse_engineering.
@wormyrocks You have to enable sending IMU data and bump up the data rate for Bluetooth, after that it'll keep sending input + gyro packets as long as you're sending vibration data over (subcommand 1/1f). I have an implementation which gets gyro data consistently here.
from nintendo_switch_reverse_engineering.
Actually this polling is incorrect. Your loop for controls should only consist of reads and you should use the fast 0x30 input format. This input format constantly pushes packets to your host.
Don't use x3 0x31 because 0x31 input reports are way bigger and take more time to construct inside the joy-con.
So, when you also send 01 output you will also receive 0x21 input reports inbetween 0x30 packets that doesn't contain 6-axis data. And these will hinder your reads.
So, the initialization should be like this:
cmd x01, subcmd x40, arg x1
cmd x01, subcmd x3, arg x30
Start read loop.
You should check when a packet received is 0x30 and only then update your 6-axis data. If the packet is 0x21 don't update 6-axis.
The best thing to do is to study the documents here and see how each report works.
Lastly, I didn't see your code, but a good practice is to use bitwise operations and masking to convert the int16 6-axis data to float. This way you minimize the latency by a lot.
EDIT:
Did some rephrasing, corrected a mistake and also:
One more thing:
If you plan to also use vibration, send it via 0x10 command (not subcommand). This way you will not receive any 0x21 packet. As @shinyquagsire23 said, you need to keep sending vibration at least every 8 input report reads (if you don't want to vibrate, just send the neutral 00 01 40 40).
PS: If you want to play with subcommands, send x3 x3F to switch back to button press mode. This way, you will only get the 0x21 reports from the subcmds and you will not accidentally read 0x30 input reports.
from nintendo_switch_reverse_engineering.
I'm also working to reverse engineer the joycons, I found this documentation. I think that Nintendo might use something similar to the joycons.
[http://wiibrew.org/wiki/Wiimote](Wiimote HID)
from nintendo_switch_reverse_engineering.
just to make you guys aware, there is a program similar to glovepie called freepie, the possibility of developing a module for the joycons may be faster/easier than an entire new driver. thanks and gj with all of this.
heres the link btw
[http://andersmalmgren.github.io/FreePIE/]
from nintendo_switch_reverse_engineering.
@alejandrorangel Cool, thanks for that. I might try and throw some of the Wiimote packets at it this weekend and see if it reacts to any of them.
from nintendo_switch_reverse_engineering.
@aspalmer That actually makes sense from the HID reports I was getting back, actually. Was able to get the HID info from the USB device, although no data was being sent. However when I paired the USB and Bluetooth together using some test code, I noticed one thing.
Over the USB, the HID protocol reports that there are 2 extra components called "Z-Acceleration, and Z-Rotation". I can only imagine this is the gyroscope and accelerometer. However, as it was over USB, no data was sent. This leads me to believe you do indeed have to send a feature report packet to the controller via bluetooth to enable the gyro/acc.
Also, via USB the HID device is reported as a "stick" or "joystick", versus the Bluetooth HID which reports as "gamepad". Can actually see this from the descriptor you sent over actually.
from nintendo_switch_reverse_engineering.
I have some notes on the Bluetooth hid buttons. The left stick & right stick buttons are adjacent button numbers. So are + - and home, capture.
It sends the stick data as hat input, though. (0-8, 8 is neutral, 0 is up) Annoying.
from nintendo_switch_reverse_engineering.
@riking What are you using to capture the Bluetooth traffic?
from nintendo_switch_reverse_engineering.
@mfosse Oh, I just straight up connected the joycon to my Linux laptop and read the input data with hidapi
. So it's default drivers.
Was about to try sending some of the 0x19 packets as OUPTUT or FEATURE reports and see what happens.
So when I hid_write
a packet with command 0x01, I get this response back:
Joycon R: Packet 0x21
C9 8E 80 00 00 00 00 00
E6 C8 6F 01 81 01 0C 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
Joycon R: Packet 0x21
8F 8E 80 00 00 00 00 00
E6 A8 6F 01 80 00 03 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
Joycon L: Packet 0x21
4F 8E 00 01 4F 9F 57 89
00 00 00 20 81 01 0C 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
Perhaps Byte 0 is the checksum? I should try calculating it.
Byte 1 is always 0x8E. Byte 2, 3, 4 is the button status.
case 0x21: // Packet 0x21
// Button status:
// Byte 1: 0x8E
// Byte 2
// Bit 0: JR Y
// Bit 1: JR X
// Bit 2: JR B
// Bit 3: JR A
// Bit 4: JR SR
// Bit 5: JR SL
// Bit 6: JR R
// Bit 7: JR ZR
// Byte 4
// Bit 0: JL Down
// Bit 1: JL Up
// Bit 2: JL Right
// Bit 3: JL Left
// Bit 4: JL SR
// Bit 5: JL SL
// Bit 6: JL L
// Bit 7: JL ZL
// Byte 3
// Bit 2: RStick
// Bit 3: LStick
// Bit 4: Home
// Bit 5: Capture
Next 3 bytes are only set by the left joycon. Next 3 bytes are only set by the right joycon. Haven't figured out what data they carry. Found the stick data! They seem relatively stable when the stick isn't moving.
from nintendo_switch_reverse_engineering.
Yup, I found the stick data.
uint8_t *pckt = buf65 + 2; // skip the HID header (0x21) and checksum byte
// print buttons...
uint8_t *stick_data;
if (jc->left_right == 1) {
stick_data = pckt + 4;
} else {
stick_data = pckt + 7;
}
uint8_t stick_unk = stick_data[0]; // maybe checksum
// horizontal stick is nibble swapped??
uint8_t stick_hz = ((stick_data[1] & 0x0F) << 4) | ((stick_data[1] & 0xF0) >> 4);
uint8_t stick_vert = stick_data[2];
printf("Stick %c: [%02X] %d %d\n", L_OR_R(jc->left_right), stick_unk, -128 + (int)(unsigned int)stick_hz, -128 + (int)(unsigned int)stick_vert);
Haven't figured out the last bit of data. It only seems to send a couple of bit patterns:
(L) 10 81 01 0C
(L) 10 80 00 03
(L) 10 80 0C 03
(L) 40 80 00 03
(R) 01 80 00 03
(R) 03 80 00 03
(R) 03 81 01 0B
Definitely not the gyro data.
from nintendo_switch_reverse_engineering.
Oooookay, looks like I'm going to need to pair the controllers before I move further - they started connecting to someone else's console, which is erroring out my Bluetooth stack.
Here's what I have so far:
https://github.com/riking/joycon/blob/master/src/joycon_input.c
https://github.com/riking/joycon/blob/master/src/joycon.h
from nintendo_switch_reverse_engineering.
Can confirm the joy-cons and pro controller do operate using the standard HID protocol, all except the gyro and accelerometer.
from nintendo_switch_reverse_engineering.
I've got a working "combine both joycons into a single controller device" program here: https://github.com/riking/joycon
from nintendo_switch_reverse_engineering.
I'm working on a vJoy feeder for the JoyCons here: https://github.com/mfosse/JoyCon-Driver
from nintendo_switch_reverse_engineering.
The Charging Joy-Con grip seems to have two interfaces with an in/out endpoint per interface for each Joy-Con. I haven't managed to get any replies from input I've sent, however the Joy-Con grip, once an HID session is started, seems to send packets matching the first MAC address handshake command for UART every time the Joy-Con are inserted and ejected. The format seems to go as follows:
81 01 <03 for eject, 00 otherwise> <inserted Joy-Con type, 01 for Left, 02 for right> <MAC>
This can also be observed from Wireshark:
The charging grip also has the same STM32 chip as the pro controller, and the same 5-pin layout found on the dock. Maybe the firmware can be dumped same as the dock to learn more about UART and Bluetooth commands @dekuNukem?
from nintendo_switch_reverse_engineering.
Guys, please see #11; I don't think the HD rumble data is HID compliant.
from nintendo_switch_reverse_engineering.
I have the firmware for the Joy-Con charging grip, doing a quick search for A1 A2 A3 A4 gets me a hit so it does seem that they talk to Joy-Con and have some sort of shim to HID. The firmware is pretty small though, 0x10000 bytes total. Willing to bet there's a point where UART and HID have to match up, that or this thing is a dedicated MAC address fetcher but I have my doubts there.
EDIT: For anyone else's curiousity, the 5 througholes are an SWD debug interface, from top to bottom:
??
SWDIO
GND
VDD
SWCLK
I also had to tap the test pad above the middle bottom screw for nRST. Dumping is pretty straightforward with OpenOCD.
EDIT 2: It seems this thing is definitely capable of sending post-handshake UART packets, and most of the handshake is done by the device, though for post-handshake packets the question is how it gets triggered I suppose:
from nintendo_switch_reverse_engineering.
Has anyone managed to read any gyroscope or accelerometer data over bluetooth? I haven't had any luck so far.
from nintendo_switch_reverse_engineering.
It seems there is indeed a set of HID commands which allow sending UART commands, however they cannot be accessed until handshaking is complete, and I'm not sure of the command to do that (seems to be done elsewhere from the main loop).
Commands which seem to exist at 0x0800BB00 are:
80 01 (Handled elsewhere? Returns MAC packet)
80 02 (Do two handshakes 19 01 03 07 00 91 10 00, 19 01 03 0B 00 91 12 04)
80 03 (Do baud switch)
80 04 (Set something to 1)
80 05 (Set something to 0)
80 06 (Something with sending post-handshake command 01 00 00 00 00 00 00 00 01 06 00 00, maybe baud related as well?)
80 91 ... (Send pre-handshake command? Has some weird lookup table stuff)
80 92 ... (Something with pre-handshake commands?)
01 ... (Send post-handshake command? Sends 0x31-large UART starting with 19 01 03 07 00 92 00 00 with checksum edited in and the rest of the HID request pinned on)
10 ... (Same as above)
EDIT: turns out the 'lookup table' stuff for 80 91 is actually for incoming UART data size, just managed to send a raw pre-handshake UART packet like such:
memset(buf, 0x00, 0x100);
buf[0] = 0x80;
buf[1] = 0x91;
buf[2] = 0x01;
buf[3] = 0x0;
buf[4] = 0x0;
buf[5] = 0x0;
buf[6] = 0x0;
hid_write(handle_l, buf, 0x7);
And the resulting data I got back was the MAC packet in a slightly different form:
81 91 00 94 01 08 00 00 3c 68 01 fd bf e8 8a bb 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
EDIT 2: Seems 80 92 actually works to a degree to send post-handshake commands (with pre-handshake headers?), this works to get something resembling an input packet, but none of the actual input shows up.
memset(buf, 0x00, 0x100);
buf[0] = 0x80;
buf[1] = 0x92;
buf[2] = 0x00;
buf[3] = 0x01;
buf[4] = 0x0;
buf[5] = 0x0;
buf[6] = 0x69;
buf[8] = 0x1F;
hid_exchange(handle_l, buf, 0x9);
EDIT 3: For the record...
Since the firmware tells me this, these are the return sizes for any 19 01 03 07 00 91 XX ... UART command:
01 - 0xF
03, 05, 06, 07, 13, anything else? - 0xB
18 - 0x37
40 - The size specified in the u16 following the XX command
from nintendo_switch_reverse_engineering.
I left my controllers on the grip for a few days and now the status packet[1] is 0x6E on the R, but it's still 0x8E on the L. Battery level?
EDIT: Docked the controller for a bit and it's back to 0x8E. Definitely a single nibble of battery
Also, noticed something weird. The kernel is always returning 0 for the number of actual bytes written 🤔 This may be why I had no response to writes other than 0x1 🤔
from nintendo_switch_reverse_engineering.
Here's what the Linux Kernel gives for the report descriptor over bluetooth:
https://www.irccloud.com/pastebin/P60ntzyH/
@shinyquagsire23 can you dump /sys/kernel/debug/hid/*/rdesc
with the Charging Grip?
from nintendo_switch_reverse_engineering.
@riking That file doesn't seem to exist for me, but the charging grip also doesn't function as a controller by default.
Also, I've managed to get a full initialization of the Joy-Con via the charging grip. The charging grip is able to send any UART command, so I am able to pull for full input at around 16ms per input, in addition to being able to dump my Joy-Con SPI firmware over HID. My HID program can be found at my repo, https://github.com/shinyquagsire23/HID-Joy-Con-Whispering
Hopefully with that, it should be possible to test Joy-Con functionality more in-depth. I did try to have the same HID commands sent over Bluetooth but it seems it's not the same protocol, unfortunately...
from nintendo_switch_reverse_engineering.
Sorry, the underscores weren't meant to be literal - replace them with the kernel-assigned device identifier.
The file should be there if hidapi can open the device, so sudo ls
the directory.
but it seems it's not the same protocol, unfortunately...
Dang :(
from nintendo_switch_reverse_engineering.
@riking Ah, I did replace the underscores but I guess I forgot to escape something and it failed, https://gist.github.com/shinyquagsire23/89ea38220e221950a233cd23f2fde28f
from nintendo_switch_reverse_engineering.
Okay, wow. Much more straightforward than the Bluetooth dump. Looks like a charging grip is almost all you need to use the joycons as a controller, I'll have to get one and add button mapping support in to my program.
Still doesn't help with the Bluetooth protocol except to reinforce that yes, 0x80 is definitely a bridge to the wires and it's definitely not available over Bluetooth.
from nintendo_switch_reverse_engineering.
Bit of a long shot, but input 33 and 129 look like pitch/yaw inputs of a gyro
from nintendo_switch_reverse_engineering.
33 is the status report (0x21) sent in reply to a 0x1 HID output report and parsed here https://github.com/riking/joycon/blob/master/src/joycon_input.c#L53
from nintendo_switch_reverse_engineering.
Do we have any way to capture bluetooth traffic between the JoyCons and the switch? Or would we need something like this?: https://www.adafruit.com/product/2269 If I get one I'll be sure to document what I find here
from nintendo_switch_reverse_engineering.
from nintendo_switch_reverse_engineering.
I was afraid that might be the case, but wasn't sure, I'll probably pick up a charging grip sometime soon and see if I can find anything.
from nintendo_switch_reverse_engineering.
Got a charging grip, but I'm going to continue the Bluetooth research.
Based on the data from the other Joy-Con I just tested with, the battery data is actually just a single nibble - 2
was low according to the console, so probably a 0-8 or 1-8 scale.
from nintendo_switch_reverse_engineering.
I also just got a charging grip, If I find anything I'll post it sometime soon.
from nintendo_switch_reverse_engineering.
just a reminder guys, feel free to submit a pull request with findings so they'll have more visibility.
from nintendo_switch_reverse_engineering.
Don't know if this help you guys but matlo, creator of gimx programmed a little bluetooth proxy here is the link https://github.com/matlo/l2cap_proxy greetings
from nintendo_switch_reverse_engineering.
Looks like the Switch is rejecting my attempts to connect to it from my computer - guess I need a BT radio that supports MAC spoofing.
Once I get that, I can do the l2cap_proxy and capture the controller data!
from nintendo_switch_reverse_engineering.
According to https://github.com/matlo/l2cap_proxy,
"The master and the device have to be paired with the bluetooth dongle."
I wasn't able to get anything to work, either; I also tried a different bluetooth mitm/proxy I found here: https://github.com/conorpp/btproxy. I might get an ubertooth one, and see if I can make any progress with that.
from nintendo_switch_reverse_engineering.
@mfosse Limited understanding of how it works on the Switch side of things, but I wasn't able to get any HID input via USB. Only via Bluetooth.
from nintendo_switch_reverse_engineering.
I'm currently trying to write some code to just communicate to a single JoyCon using an L2CAP Bluetooth socket, and can get it to respond to some commands, but the responses seem meaningless to me and I can't get it to send me input data, have you all figured out how to properly get it to send data just over Bluetooth on a BT socket?
from nintendo_switch_reverse_engineering.
Hi, im not a programmer, but does anyone here know a way to control the nintendo switch using a pc and a generic controller. Either having the switch recognizing the input as a procontroller or as joycons?
from nintendo_switch_reverse_engineering.
from nintendo_switch_reverse_engineering.
from nintendo_switch_reverse_engineering.
from nintendo_switch_reverse_engineering.
elandsboy92, I would be happy to help you by soldering a pair of joycons. Do you have specs for your controller, an interface or pinout or something?
from nintendo_switch_reverse_engineering.
I am also interested. Is there any layout for the board ?
from nintendo_switch_reverse_engineering.
It looks like the following BOM cost, ignoring shipping, would be the price to build 3 of the boards (since the minimum order is 3 PCBs):
3x PCB from OSH Park - $7.15
3x STM32F072C8T6 from Mouser - $9.45
6x ADG714 from Mouser - $29.52
3x AT24C08D (EEPROM) from Mouser - $1.08
6x MBR120 Schottky diode from Mouser - $2.22
3x sot23-5 voltage regulator - $0.36
3x USB Micro-B connectors from Sparkfun - $4.50 (they're currently sold out, might be able to source elsewhere)
6x KMR2 switch from Mouser - $2.10
the other resistors, caps, and jelly beans maybe $10 or something
Considering all of that, the boards are approx $20-$25 each. Might be able to do a group buy to bring the cost down. I'm not sure what resistor and capacitor values you need.
That doesn't take shipping or labor/time into account, which would drive the price up as well. I do think it would be awesome to get elandyboys92 the ability to play the switch with his custom controller 👍
from nintendo_switch_reverse_engineering.
AUmrysh My controller is pretty flexible, you can check the user manual here: https://docs.google.com/document/d/1I4GtzR9qVmfWkX-bSEiWwPzeTTwI0vBQqb-P3fBXsk4/edit#heading=h.f2fylzjkqgrc
Basically you can connect it to pc, wii, wiiu, xbox360, xboxone, ps2, ps3, and ps4 using the usb, and/or different adapters (like cable adapter and cronusmax that i do have)
I can program buttons to be held, turboed or switch them from position. Heres a picture of the back of the controller:
Which is the pinout for the expansion port, but I made a db25 cable and checked for continuity and the programming I make in the controller wont work, so that would be like my last resort.
You can check more details of my controller here:
http://www.broadenedhorizons.com/ultimate-arcade2
https://www.youtube.com/watch?v=h9dm2prcSL0
https://www.youtube.com/watch?v=iQznFavtekw&t=4s
Ideally, I´d connect it via usb to the switch or connect it to the pc and have the pc send info to the soldered joycons. If you have questions you can email me at [email protected]
Thanks!
from nintendo_switch_reverse_engineering.
ReconDaemon I would easily pay those $25+ shipping/labor if someone is interested :v
from nintendo_switch_reverse_engineering.
AUmrysh Oh, I also have this file with the values of an HIDTest i did on my controller
UA2.txt
from nintendo_switch_reverse_engineering.
Does someone have a transparent usb proxy ?
https://github.com/matlo/serialusb Doesnt work with Switch Update 3.0 because the controller doesnt register via usb on a pc to start the usb proxy.
Looks like he needs to talk via bt to the switch before switching to usb mode.
from nintendo_switch_reverse_engineering.
I would like to point out the following project, which uses an expanded version of the pokken controller descriptors to allow for analog sticks, and access to all buttons. This could prove useful to anybody trying to create custom wired controllers for the Switch, as long as they don't need HD rumble, NFC, or gyros: https://github.com/progmem/Switch-Fightstick
Not particularly useful for the other main use cases of this reverse engineering ( like custom bluetooth controllers, or analog/gyro on a pic from the joycons), but thought we probably want to note this here since this seems to be the most complete repository of reverse engineering information.
from nintendo_switch_reverse_engineering.
@elandyboys92 @ReconDaemon i too would be interested in one/two of these boards albeit i live in uk so shiping would be ££
from nintendo_switch_reverse_engineering.
Nobody has a HORIPAD wired controller to dump the usb HID descriptor ?
from nintendo_switch_reverse_engineering.
There's a copy of the descriptors in this project https://github.com/progmem/Switch-Fightstick/blob/master/HORI_Descriptors
from nintendo_switch_reverse_engineering.
I think that this HID descriptor is about the HORI pokken controller without analog stick. I wanted to speak about this HORI gamepad with analog : https://www.amazon.com/Nintendo-Switch-HORIPAD-Controller-Officially-Licensed/dp/B01NAUATSM
from nintendo_switch_reverse_engineering.
My mistake, didn't read between the lines. Here is a fresh dump of the descriptors when I plug the controller into my pc (it also sends full button inputs to jstest-gtk compared to when I plugged a Nintendo branded Switch pro controller in and got its USB descriptors)
https://gist.github.com/jwiki95/86dcf36103ce799b3e262ed7b4245da6
from nintendo_switch_reverse_engineering.
Thank you very much ! I will be able to test this HID descriptor in this AVR program "https://github.com/progmem/Switch-Fightstick" to check if analog sticks can be emulated on switch compared to the pokken descriptor.
from nintendo_switch_reverse_engineering.
from nintendo_switch_reverse_engineering.
Yeah the HORI gamepad is just a plain USB HID gamepad and the converters pretend to be HORI controllers. The Pro Controller and Joy-Con have custom protocol for things like HD rumble, motion, NFC and LEDs, so it's harder to spoof an official Nintendo controller.
from nintendo_switch_reverse_engineering.
I have tested this Horipad descriptor with the Switch-Fightstick AVR program and it works. Analog sticks are recognized on the Switch. The aim is to do as the "brook supreconverter", ps4 gamepad to Switch using arduino USB host shield with bluetooth dongle.
from nintendo_switch_reverse_engineering.
Hey all,
I've started my own Joy-Con driver, cribbing heavily from @mfosse 's driver, with a heavy focus on 6-axis data and HD Rumble. I'm trying to go with a minimal interpretation to be as clean, fast, and lightweight as possible - I only need to use one Joy-Con at a time, I only ever want a wireless connection, and I don't care about a GUI.
I have a couple questions about how to get gyro data out of the Joy-Cons. Both Matt's driver and the code that I wrote have at one point or another dumped what appeared to be gyro data in return packets, but as I fiddled with the parameters the gyro data would start and stop working seemingly at random. The two things I changed were as follows:
- I played around with sending subcommand 0x01 versus 0x1f; this was based on Matt's implementation here, but I couldn't find any other documentation mentioning it.
- In setting up the input reports, I wasn't sure whether to use report mode 0x30 or 0x31. Matt's driver uses 31, but since I don't care about NFC it seems like 0x30 would make more sense. Ultimately not sure if it made any difference.
In any case, in the first few permutations of these changes my Joy-Cons would occasionally spit out packets with ID 0x31 and what appeared to be gyro data (when I moved the Joy-Cons the numbers changed); however, after a few more changes it seems like now I can only get stick and button data, and I'm not sure what combination actually worked correctly.
It's also worth noting that I don't have a proper polling loop set up at this point -- all my driver does is repeatedly send subcommand 0x01 (or 0x1f) and then dump the responses (Matt's code uses a hid_exchange helper function which does a write immediately followed by a read). So it might be that the packets with the gyro data are being sent asynchronously and I'm just missing them? But I'm not sure.
Anyways, if anyone has guidance on what might be going on I'd be really grateful. It's worth noting that I noticed this kind of intermittent behavior with Matt's driver before I started hacking on my own version, so if it's an as yet unsolved problem I'll be sure to document my findings. I'm happy to post my code, but it's a pretty ugly Visual Studio project right now and I haven't gotten around to cleaning it up for version control.
Thanks!
from nintendo_switch_reverse_engineering.
Please read the documentation here.
The x02 at the end is the subcmd that requests device info.
You need to reply to this with a 0x21 input report.
To register your controller you need to forge the following subcmd replies when asked:
- Send
82 02
reply that contains a forged device info - Send
90 10 00 60 00 00 10
spi reply that contains a forged serial number or just zeroes - Send
80 08
reply (ack for receiving the set shipment command) - Send
80 03
reply (ack that you changed input report format)
Now you need to start sending forged 0x30 input reports every 15ms. I don't know what switch will do if you don't, so try both.
- Send
83 04
reply that contains the elapsed time after pressing a trigger. Better not be zero. - Send
90 10 80 60 00 00 18
spi reply that contains forged Factory Sensor and Stick device parameters - Send
90 10 98 60 00 00 12
spi reply that contains forged Factory Stick device parameters 2 - Send
90 10 10 80 00 00 18
spi reply that contains forged User Analog sticks calibration. Send zeroes. - Send
90 10 3d 60 00 00 19
spi reply that contains forged Factory configuration & calibration 2. - Send
90 10 20 60 00 00 18
spi reply that contains forged Factory configuration & calibration 1. - Send
80 48
reply (ack that you enabled vibration) - Send
80 40
reply (ack that you enabled 6-Axis sensor) - Send
80 30
reply (ack that you set Player lights) - Send
80 48
reply (ack that you enabled vibration again)
Congrats, you just paired your device with Switch.
Have in mind, that if switch lost a packet it will send the same command again. So you should send them according to the output report you received from Switch. Not sequentially.
from nintendo_switch_reverse_engineering.
Thank you very much! I did find that page, and right now I was formatting a reply to the 0x02 subcommand like this
0x21 //report id
0x01 0x8E //counter / battery / connect id
0x84 0x00 0x12 //buttons
0x01 0x18 0x80 //stick
0x01 0x18 0x80 //stick
0x80 0x82 0x03 0x48 0x01 //subcommand ack, firmware version, etc
0x02 //"always 2"
0xA2 0x55 0x79 0xAB 0x78 0xCC //MAC
0x01 0x01 //"always 1, 1"
The switch does not seem to reply to that though. Every 10th time I send a 0x21 report, it resends its same 0x02 subcommand with the counter field incremented by one.
I have formatted the first two bytes of my response as 0x80 0x82 based on what I read, but you have used 0x82 0x02. I think this is probably the one thing I am missing, I will continue messing around. Thanks again.
from nintendo_switch_reverse_engineering.
that's the problem. 80 is the ACK and then always followed by the subcommand. If the reply has data in it, you sum the command to ACK, hence the 82.
But after that you always have the command as I said. So change it to 82 02.
Basically the MSB signifies the ACK. The other bits tell the switch to expect a specific type of data after the ACK and subcmd bytes
from nintendo_switch_reverse_engineering.
Thanks, Ill test tomorrow hopefully. Should this document be revised or am I just reading this wrong?
from nintendo_switch_reverse_engineering.
You are welcome. It will be revised.
from nintendo_switch_reverse_engineering.
I got it running right now. The docu is correct, just a bit unclear. the subcmd value is in 2 consecutive bytes of the "80 82 02" sequence. byte 13 of the subcmd report section should say that it is always the subcmd ID
from nintendo_switch_reverse_engineering.
Well actually I guess its more complicated than that.
I did get it working, I am now paired up and controlling the system with 100% homemade hardware and software.
I posted a log here for those who come after me https://github.com/timmeh87/switchnotes/blob/master/console_pairing_session
I was actually able to pass only zeros for all of the SPI reads. Obviously this is not ideal, but pleasing to me none the less.
Regarding the I2C reads, I see that the memory ranges 0x6000 to 0x6100 and 0x8000 to 0x8100 (approximately) are used for some kind of personalization data? Is there any knowledge of what the memory map is? Using my own setup I can only emulate a 64k address space. Im guessing the lower 64k is the block I want to remap, but I was wondering if maybe its better to remap 0x6000 - 0x16000 ?
I think I can use the existing JoyCon Tooklit V2 to use a dump of my own memory to obtain values for these writeable memory regions. Is that correct?
from nintendo_switch_reverse_engineering.
Yep.
Again, check documentation in here. Almost all SPI is documented.
from nintendo_switch_reverse_engineering.
Is there a preferred input report mode the Joy-Con ought to be in when reading SPI data? I have a feeling that having it constantly in mode 0x30 means that replies to SPI reads sometimes don't happen.
from nintendo_switch_reverse_engineering.
Yes, the cleanest one: 3F.
It's what I use in my app and also the default when you wake a Joy-Con or Pro.
But you won't be able to control the Switch, as it pushes normal HID input report when a button is pressed.
So tell switch that you changed input report, and after the whole procedure, then switch to 30.
Tell us then, if it tries to send a 03 30 subcmd again.
About the revision for all reports except 3F check here: https://github.com/CTCaer/Nintendo_Switch_Reverse_Engineering/blob/patch-1/bluetooth_hid_notes.md
After finalizing it, I will make a pull request.
Lastly, I have a request from you, if it is possible.
"Turn off" the connection with your special adapter, so it doesn't show up inside Switch but it can still receive or sniff packets and go to Switch' controllers menu. Then try the Find option and sniff what packet sends to wake up the controllers.
EDIT:
Btw, don't get confused. I'm actually replying to both of you, as the above info is generic and important.
from nintendo_switch_reverse_engineering.
Haha, I just spent 3 minutes trying to figure out which one of us you were asking about the wake report.
Im very new to this whole switch thing, including the menus and everything. Right now I am paired up with the switch console, and I am receiving a slow steady stream of "0x10" output reports from the console. I am ignoring them, as i am perfectly able to control the buttons without dealing with the 0x10 stuff for now (a quick glance suggests it might just be trying to get me to rumble, and failing)
What is the exact procedure as far as the switch console's menus and reports that I should send to the switch from my fake-joycon? I can post full HID traffic logs for whatever procedure I do.
Spcifically Im unsure what "turn off" means. Is that a report I should send, or do I terminate the actual bt connection from the joycon or something?
Apologies in advance, It might be a day or two before I can get back to playing with this
from nintendo_switch_reverse_engineering.
The 0x10 output report is only for vibration.
You must not reply to them because it doesn't expect to have a reply.
Switch periodically sends them every 8 0x30 received. Basically every 120ms.
For the wake up controller thing:
Main screen -> Controllers -> Search for controllers.
And you select your grayed out custom controller.
This sends some command to a turned off joy-con/pro and wakes it up.
from nintendo_switch_reverse_engineering.
I did some testing now. It might be me, but this feature seems really buggy.
Long story short, I do not have an answer. Keep reading though, maybe you could help.
Specifically, read the last few lines about EEPROM/BDADDR and tell me what you think?
Log of work is here https://github.com/timmeh87/switchnotes/blob/master/Find_Controller_notes
from nintendo_switch_reverse_engineering.
I just had a thought.. Could you whip up a version of the Joycon Tool 2.0 that will only restore the critical memory areas from a backup? I cant find the source code.
I can use it to write colors just fine, so if I write the critical memory areas (with my own BDADDR inserted), maybe that would help things along and remove uncertainty
I have the lower 64k of address space emulated, but there is only actually around 2k of memory so I cant restore the first part of a backup sequentially and get to 0x8000.
Although, according to my theory, I should only need the first 0x1000.
from nintendo_switch_reverse_engineering.
You only need to emulate the data @x6000. It's the only one needed. To be true, all zeroes can do the trick if you have a correct x02 reply.
In SPI:
S/N does not matter
color does not matter
the type of controller does not matter (it is used from the controller to produce the number in the x02 reply, after fw)
stick/sensor configuration/calibration does not matter (except if you want to emulate control sticks)
In a real jc/pro you can only write between x6000-xFFFF. So you can't overwrite the BDADDR.
The Joy-con never turn off with SYNC button, they just go to low power/suspend mode (they don't maintain the connection though).
You need to send a specific subcmd to really turn them off (x07).
You sent your real bt address with the x02 reply when you paired the first time (switch reads the BDADDR from there, not from SPI)?
If not, go to Settings and disconnect all controllers and connect and send a good x02 reply again.
I just tested and found out that the joy-con don't wake up if you previously connected them to another device.
So they probably stay on at an extremely low power receive only mode. And when they receive the 0x10 command they wake the SoC and wake up completely. But they accept only packets from the last connected host (saved @x2000 in SPI).
Otherwise, is it possible for your setup to receive packets meant for it's MAC without a connection?
You probably can try this by connecting a joy-con to your special adapter, then "turn it off" and send a x10 command to it's bt address.
I can write you all the correct replies if you are willing to share some of your code and the bt address you are using. Hit me an email.
EDIT:
Btw, all devices in search for a controller, get different patterns to distinguish them. Some in reddit, started crying for production differences when they used it. But little did they know..
from nintendo_switch_reverse_engineering.
Hm ok. I think you are right that the BDADDR @~0x0000 memory is never actually read by the switch console, and therefore does not play a role in this. It can be seen from the handshake that it does not.
I believe the BDADDR I am passing on the initial 0x02 subcmd is correct, but its probably worth a shot to reverse it just in case (The CC module has a mac address that starts with 0xCC [cute, right]. The 0xCC is the last byte in the MAC field, So I think it is already correct, right? You can see what I send in my log file)
There is maybe also another clue in my previous handshaking log...
rcvd: 0x01 0x0D 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Received subcommand 06 : Reset connection (Disconnect)
Sent: 0x21 0x07 0x8E 0x84 0x00 0x12 0x01 0x18 0x80 0x01 0x18 0x80 0x80
0x80 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
It looks like the bluetooth connection should be disconnected after that, right (i didn't implement this command, i just reply to it, so I don't disconnect at this point)
If the status of the bluetooth connection before "Find"ing is "not connected", then the "Find" process must first establish a bluetooth connection.
I have a theory: when pairing, you must put the joycon into a pairable mode where it advertises its presence, right? And then it gives out its BDADDR during the handshake. Well the joycon could theoretically still be in a "connectable" state without advertising. I think the most sensical thing is that the switch would simply attempt to connect to the BDADDR of a controller it thinks it should be paired to. If the connection is successful, it simply sends some rumble. It wouldnt even necessarily require a "wake up" command, since establishing a new bt connection would probably wake up the joycon anyways.
as an addition to the theory, if the joycon will only accept connections from the last console it was paired with, even though when you turn they joycon on it will try the last 3 (i believe). It depends on the connection direction. This is so you cant hijack your friends shit while they are playing (??)
This is all just a theory.
According to this theory, the console is trying, but failing, to connect to me. for some unknown reason, which might simply be my janky code.
I was talking to a co-consiprator of code today about creating a proper bluetooth sniffer, but right now Im limited to simple stack operations like pairing and advertising and sending data. Partly because Im almost as new to the bluetooth as I am to the switch console, Partly because my stack does not expose the full suite of vendor HCI commands, as far as I know. A sniffing solution would be months away so we cant rely on it now.
from nintendo_switch_reverse_engineering.
BTW, this Arduino library has some very useful functions that can be drag-and-dropped by anyone wishing to process IMU input from the LSM6DS3 in the Joy-Con.
from nintendo_switch_reverse_engineering.
The switch still uses the MAC address from the bluetooth initialization though.
The MAC address from the joy-con initialization (x02, etc) is used elsewhere.
For some reason, everything in x02 reply is in Big-Endian.
So if your first byte in your MAC address is xCC then it should be 0xCC 0x78 0xAB 0x79 0x55 0xA2 and not what you sent.
Your theory about "connect-able" without advertising seems to be the reason.
Also the joy-con only saves one host MAC (not 3). There's no way to connect to it if it doesn't have your MAC in it's SPI. Correct your MAC in Big-Endianness for x02 and try again.
from nintendo_switch_reverse_engineering.
Some notes from today:
-
The procedure to reproduce is this:
-- pair a new joycon to the console, press the required buttons to finish pairing
-- confirm constant rumble command is being received
-- sleep the console with the "POWER" button, confirm that hid connection was closed by console
-- wake the console up, go to "Find" screen. All prev. paired controllers are now grey
-- press on the controller and wait to see what happens. -
So far, nothing has happened on the fake-joycon end. After I pair and disconnect, I can never get it to send me anything from the "Find" screen. I can re-connect by rebooting the fake-joycon, but the console seemingly still wont initiate communication
-
The console for sure uses the BDADDR in the 0x02 subcmd to differentiate between joycons. I tried reversing the address and restarting, and I now have two fake joycons showing up in the "Find" menu.
-
When I give the MAC in big-end format, CC..... the console will search for about 8 seconds and then return with a
"?"
-
When I give the MAC in little-end format, ......CC, the console searches for much longer time. it seemingly never stops.
-
I interpret this result to mean that the CC...... MAC format is correct, because the console finds something at that address and fails to talk to it. When it looks for the ......CC address, it keeps searching as if you were walking around your house waiting to see that device in range, but it never finds it, cause the address is backwards.
Buuuut perhaps the exact opposite interpretation is also possible. Either way the only way I can re-connect the fake-joycon is to start the connection from the joy-con side (ie, as if by pressing a button on a real joycon)
- Next avenue of exploration: I believe The HID protocol has features for setting a device to sleep/wake. (specifically, "remote wake == true" in the SDP record) Perhaps nintendo is directly tapping into this? Im not sure how it works
from nintendo_switch_reverse_engineering.
Yep, CC...... is the correct way to go.
Btw, in windows when it sleeps, it doesn't send any packet. At least something that passes to OS, so I can capture it.
I have another request: Joy-Con firmware update.
Try to change your x02 reply with x01 x20 as fw version instead of x03 x48.
Then try to use "Update Controllers" for Controllers and Sensors in Settings.
EDIT:
About remote wake, you mean HIDRemoteWake? This is to wake up the host as far as I can see.
from nintendo_switch_reverse_engineering.
Hm, about the "Find" thing, Im kind of at a dead end of ideas here, other than Im pretty sure it involves actually opening a bt connection that was previously closed, or "parked" or something. If your code only deals with HID API stuff now, you might have to go a level down to try into the bluetooth layer stuff and try to initiate a connection to a prev paired device? I wouldnt be surprised if my bluetooth has something wonky about it; maybe you can wake up a joycon now if you try some of these new ideas?
Firmware update: As soon as my controller pairs, I get a popup to the effect of do you want to update the firmware right now
. I click "Yes" and then get this over bluetooth:
HID Set Report Indication, ReportType: rtFeature, ReportLength: 1,
Report: 0x70
This "Set Report Indication" is not the same type of message as a "Data Indication" (im using stock example code here, but I think that's a real term from some spec somewhere). I dont have a handler for these types of things.
I guess if you dont know what the reply is, you could send this to a joycon and see what it says back
from nintendo_switch_reverse_engineering.
This is the API page from my own stack for what "set report indication" is
Control Channel transfers have two phases, a Request by the host and a Response by
the device. Only ONE host control channel Request shall be outstanding at a time.
Reception of a HID Set Report Confirmation event indicates that a Response has been
received and the Control Channel is now free for further Transactions.
So I assume it would simply expect a "set report response/confirmation" in return. The 0x70 appears to be "data"
Furthermore, in the response, the possible replies are:
typedef enum
{
rtSuccessful,
rtNotReady,
rtErrInvalidReportID,
rtErrUnsupportedRequest,
rtErrInvalidParameter,
rtErrUnknown,
rtErrFatal,
rtData
} HID_Result_Type_t;
although its not clear if those are integers, or bitmasks, or just a made-up enum.
from nintendo_switch_reverse_engineering.
I knew it! output report x70 is to initiate the firmware update!
I'll try to find how to reply on this so we can see the next output report from Switch.
Currently, I just use a commercial BT adapter, so I'm bound to HID stuff only.
Do you have any dev board that supports dual mode and bt 4.x that you can propose to me?
from nintendo_switch_reverse_engineering.
I dont know if this helps or if you are already reading this
https://msdn.microsoft.com/library/windows/hardware/ff539684
from nintendo_switch_reverse_engineering.
Im on the CC256x platform, there is dev hardware available
from nintendo_switch_reverse_engineering.
Thanks. I'm reading this now
http://processors.wiki.ti.com/index.php/CC256x_TI_Bluetooth_Stack_HIDDemo_App
It says that you need to reply with a GetReportResponse and maybe use rtSuccessful (=0).
from nintendo_switch_reverse_engineering.
You got it.
It looks like the "data" in this response is an entire report descriptor, so we will probably need to induce a reponse from a real joycon to see what that is
Stock example "mouse" code boils down to this:
HID_Get_Report_Response(BluetoothStackID, HIDID, /*connection params */
int, int, /* result type, report type. Probably "rtSucessfull, 0x70" */
sizeof(GenericMouseReport), GenericMouseReport); /* this is an entire report descriptor for a mouse */
EDIT: sorry, i misread, this is the entire REPORT, not the descriptor
from nintendo_switch_reverse_engineering.
hold on a sec, I think we should be looking at
SetReportResponse [ResultType]
rather than
GetReportResponse [ResultType] [ReportType]
Since "set report response" pairs up with "set report request"
The argument is just a single byte, probably 0x70
from nintendo_switch_reverse_engineering.
Related Issues (20)
- Pin 4 under console reset condition
- how to prevent auto-sleep?
- compile a list of joycon drivers and modules from different languages? HOT 2
- How to solve Subcommand 40 02
- Is there a list of Clone controllers which you have found to work (or not work) when plugged into other hosts?
- HD Rumble is not on par with the Switch
- Pinout for the joycon rail flex cable specifically? HOT 6
- When all USB ports are not working on dock HAC-007
- Do you know anything about switch game cards? I'm trying to use reverse engineering in one HOT 5
- Enabled HID Gyro/Acc over Bluetooth
- Wired joy con wired status response expansion
- Joystick operating voltage HOT 1
- Payloads HOT 1
- Anyway to reverse A/B X/Y
- About Pro controller/Joycon LTK error ,ask for help
- How do I test the the joycon buttons with a multimeter
- [Nintendo Switch.com]
- Joycon not connecting to Switch, powering up or charging/PCB issue? HOT 3
- Joycon L&R PCB dimensions
- 8Bitdo Ultimate Controller doesn't work via Bluetooth on Linux
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nintendo_switch_reverse_engineering.