Comments (31)
Analysing the four unused bit(first byte lowest 2 bit and last byte highest 2bit),
I found there are other types of rumble data.
Though it is not perfect yet, I summarize my analysis here.
basically, the JoyCon HD rumble is a mix of below three elements:
Resonance Frequency Wave
Sin wave of a resonance of haptic reactor.
Frequency is 160Hz or 320Hz.
Amplitude is 4bit.
Arbitary Frequency Wave
Sin wave of a arbitary frequency.
Frequency is 7bit, 40-625Hz for low frequency or 80-1250Hz for high frequecy.
Amplitude is 7bit or 4bit.
Click Pulse
4 kind of fixed shape transient pulse at the rumble beginning.
pulse period is 10msec.
shape is 4 type.
Amplitude is 4bit or 7bit.
the rumble data is the combination pattern of these three elements in special manner.
TYPE X0: "single wave with resonance"
In this type, you can make one arbitary frequency wave and one resonance wave and two pulse.
BIT PATTERN:
bbbbbbba eeedcccc ihggggfe ?0iiiiii
a High/Low select bit (0=low channel, 1=high channel)
bbbbbbb Frequency
cccc High freq channel amplitude
d High freq channel switch
eeee Low freq channel amplitude
f Low freq channel switch
gggg pulse1 amplitude
h pulse1 switch
iiiiiii pulse2 amplitude
if [a]=0, the [bbbbbbb] is the frequency of "low channel" and "high channel" frequency is 320Hz.
if [a]=1, the [bbbbbbb] is the frequency of "high channel" and "low channel" frequency is 160Hz.
if [d]/[f]/[h] bit is "1", the output of correspond channel is off(become silent).
I cannot figure out the last bit.
TYPE 01-00: "dual wave"
In this type, you can make two arbitary frequency sin wave at the same time.
BIT PATTERN:
aaaaaa00 bbbbbbba dccccccc 01dddddd
aaaaaaa High channel Frequency
bbbbbbb High channel Amplitude
ccccccc Low channel Frequency
ddddddd Low channel Amplitude
TYPE 01-01: "silent"
no sounds at all.
BIT PATTERN:
??????01 ???????? ???????? 01??????
TYPE 01-01: "dual resonance with 3 pulse"
In this type, you can make 2 resonance frequency sin wave and 3 pulse at the same time.
baaaa?10 eeedcccc ihggggfe 01iiiiii
aaaa High channel resonant(320Hz) amplitude
b High channel resonant(320Hz) switch
cccc Low channel resonant(160Hz) amplitude
d Low channel resonant(160Hz) switch
eeee pulse 1 amplitude
f pulse 1 switch
gggg pulse 2 amplitude
h pulse 2 switch
iiiiiii pulse 3 amplitude
if [b]/[d]/[f]/[h] bit is "1", the output of correspond channel is off(become silent).
I cannot figure out the one bit meaning.
TYPE 11: "dual resonance with 4 pulse"
In this type, you can make 2 frequency sin wave and 4 pulse at the same time.
cccbaaaa gfeeeedc iiiihggg 11lkkkkj
aaaa High channel resonant(320Hz) amplitude
b High channel resonant(320Hz) switch
cccc Low channel resonant(160Hz) amplitude
d Low channel resonant(160Hz) switch
eeee pulse 1/400Hz amplitude
f pulse 1/400Hz switch
gggg pulse 2 amplitude
h pulse 2 switch
iiii pulse 3 amplitude
j pulse 3 switch
kkkk pulse 4 amplitude
l pulse 4 switch
if [b] bit is "1", the "320Hz" is off and "pulse1/400Hz" channel make "400Hz" sin wave.
if [b] bit is "0", the "320Hz" is on and "pulse1/400Hz" channel make "pulse".
if [d]/[f]/[h]/[j]/[l] bit is "1", the output of correspond channel is off(become silent).
Amplitude:
the "Amplitude" bit pattern is 7bit or 4bit.
7bit amplitude:
"0000000" is minimum and "1111111" is maximum amplitude.
this pattern is used on "arbitary freq channel" or last "pulse"
4bit amplitude:
"0000","1100"-"1111" is silent, "0001" is maximum, "1011" is "minimum.
below table is normalized value measured by oscilloscope.
0000: 0
0001: 1
0010: 0.713429339
0011: 0.510491764
0100: 0.364076932
0101: 0.263212876
0110: 0.187285343
0111: 0.128740086
1000: 0.096642284
1001: 0.065562582
1010: 0.047502641
1011: 0.035863824
1100: 0
1101: 0
1110: 0
1111: 0
Pulse Shape:
there are 4 pulse shape.
pulse 1:
three peaks and three valley. length is 10msec.
(medium peak, medium valley, large peak, large valley, small peak, small valley)
pulse 2:
one peak and two valley. length is 10msec.
(valley, peak, valley)
pulse 3:
time shift of pulse 1.length is 10msec.
pulse 4:
sum of pulse 1 and pulse2.
from nintendo_switch_reverse_engineering.
The freq was indeed a mix of educated guessing (Frequency modulation), testing and later confirmed by RE.
The amplitude works similarly but actually it's broken in the following 3 parts:
0
0.009942 - 0.112491,
0.117471 - 0.224982,
0.229908 - 1.0
or in a 0 1-100 range based on supported amps by JC:
0,
1-16,
17-100
This is the latest data I found out by REing.
You can also see this behavior by the following chart:
Lastly, don't take my values as the exact real ones. If you can find similar values it's OK.
We would be grateful if you can crack the algorithm.
from nintendo_switch_reverse_engineering.
Well, finding the algorithm for low amplitude was a lot easier having known the algorithms for high amplitude:
uint8_t encoded = round(highAmplitudeAlgorithm(amp)) / 2;
uint8_t evenOrOdd = encoded % 2;
uint8_t bytes[2];
if (evenOrOdd > 0) {
// odd
bytes[0] = 0x80;
encoded = encoded - 1;
}
encoded = encoded / 2;
bytes[1] = 0x40 + encoded;
// if you wanted to combine them:
uint16_t byte = (bytes[0] << 8) | bytes[1];
from nintendo_switch_reverse_engineering.
Sorry, val
is supposed to be encoded
. I'll edit that.
from nintendo_switch_reverse_engineering.
When the Bluetooth stack of the joycon and your computer desync (or whatever that is), just do a physical pair with your Switch, long press the sync button, and connect again from your computer.
from nintendo_switch_reverse_engineering.
@lyra833 could you post what you sent to the JoyCons / their responses? I haven't been able to get any rumble events to trigger
from nintendo_switch_reverse_engineering.
I've been testing vibration a bit today by keeping the baudrate lower over USB HID so that I can race fast enough to keep vibration enabled when transitioning from Bluetooth to UART in the grip and found a few things at least:
For a USB HID packet 80 92 00 0a 00 00 eb 01 10 03 XX YY YY YY XX ZZ ZZ ZZ
,
The right Joy-Con is only affected by the ZZ bytes when incrementing each byte one at a time from 0 to FF, and the left Joy-Con is only affected by the YY bytes when doing the same. In this test, XX are both sent to 01.
When leaving YY or ZZ at 0x80 and incrementing the first XX or the second XX respectively, only the first YY or ZZ respond and the frequency of the vibration increases. Leaving YY or ZZ at 0x01 has all of the bytes respond. The first XX seems to control frequency on the left Joy-Con only, and the second the right. This test is demonstrated here and the code here
from nintendo_switch_reverse_engineering.
The HD-Rumble is well known now. Can we close this?
from nintendo_switch_reverse_engineering.
I've started trying to decode the amplitude algorithm (for high amplitude first), and I've got something that partially works (only for 0.010
through 0.033
, though): ((log2(amp * 1000) * 32) - 0x60) / (5 - (amp * 30))
. The fact that it works only for these values is probably due to some of the fixed numbers I've used (0x60
, 5
, 30
). Anyone know how the correct equation for frequency was found? Or was it just educated guessing and testing?
EDIT: BTW, the correct values are given if you round()
the output
from nintendo_switch_reverse_engineering.
Alright, so I've found the algorithm(s) for original amplitude to high amplitude, and they are (unsimplified):
if (amp < 0.117) return (((log2(amp * 1000) * 32) - 0x60) / (5 - (2 ** amp)) - 1);
if (amp >= 0.117 && amp < 0.23) return ((log2(amp * 1000) * 32) - 0x60) - 0x5c;
if (amp >= 0.23) return (((log2(amp * 1000) * 32) - 0x60) * 2) - 0xf6;
Each range (0
to 0.117
, 0.117
to 0.23
, and 0.23
and up) requires it's own variation of the algorithm. Basically, what appears to be the encoded amplitude is ((log2(amp * 1000) * 32) - 0x60)
. I'm going to start figuring out the algorithm(s) for low amplitude later today/tomorrow.
These equations should obviously be simplified and cleaned up, but I literally just now found them so... I'll leave that to someone else. 😄
from nintendo_switch_reverse_engineering.
where does val
come from in this alg?
from nintendo_switch_reverse_engineering.
Also, @CTCaer, I figured I might as well mention this here because I wasn't sure where to put it, but I'm having trouble applying the equations on this page to return the default rumble data [00 01 40 40] from input value of f=320 Hz, amp=0. My low frequency value ends up as 0x60
instead of 0x40
when I pass in f = 320 Hz. Are you certain that the low frequency conversion equation shouldn't be uint8_t lf = encoded_hex_freq - 0x60
rather than uint8_t lf = encoded_hex_freq - 0x40
?
from nintendo_switch_reverse_engineering.
Hmm the equation is correct.
The default values are [00 01 40 40] = [HF: 320, 0.0 | LF: 160, 0.0]
Default LF is 160Hz. That's the Low end resonant frequency.
320Hz is HF default and also High end resonant frequency.
EDIT:
@facekapow
I will try your algorithms when I have time. As, I said, they don't need to be the exact same algorithm that Switch uses. We just need them to spit out similar numbers.
If these are working we can optimize them later.
(I'll also try to optimize them in calculation expense way.
E.g in freq alg: / 10.0
can be * 0.1
.
Multiplication is way less expensive than dividing with double/float )
from nintendo_switch_reverse_engineering.
OK, so those two default frequency band values don't correspond to any real initial frequency value?
For instance, I can't start with some overall frequency F to give me LF = 160 and HF = 320. Because if I plug in HF = 320 and LF = 160 and try to solve for encoded_hex_freq I get two different answers.
from nintendo_switch_reverse_engineering.
Ofcourse. You should get different values for encoded_hex_freq and for encoded LF/HF freq.
OK, let's decode the default vibration [00 01 40 40]:
One way to do this is:
HF_u16 = 0x0001;
HF_freq = (HF_u16 >> 8) & 0xFF | HF_u16 & 0x01; //we need LSB
HF_ amp = HF_u16 & 0xFE; // we mask the LSB out
Another way we can work with HF_amp is (HF_u16 >> 1) & 0xFF and then we get a range of 0-7f with +1 increments.
LF_u16 = 0x4040;
HF_freq = (LF_u16 >> 8) & 0x7F // we mask out x80 which is the intermediate for LF_amp
LF_amp = LF_u16 & 0x80FF // we also get the x80 from HF_freq
Then for LF_amp we can work by splitting the 2 bytes. And if LF_amp >> 8 == 0x80 then we know it's intermediate amplitude and bigger than LF_amp & 0xFF.
I may sound a bit confusing, but that's the math. Please also read here, to understand which byte is which and how they are encoded.
Lastly, don't take my code as the de facto. There are countless ways to smartly optimize, bit mask, bit shift, convert and work on data. This way you can have easier calculations and also less expensive.
The above also means, that we can find better algorithms with new numbers that increment by +1 and then bit shift them to have what JC understands. Bit manipulation is a funny thing..
from nintendo_switch_reverse_engineering.
OK, I've read your comment again. If understood correctly, you want to work with only one algorithm for both LF/HF.
As you probably saw by now:
No you can't. You need to have 2 different algorithms (functions) when you do the encoding.
from nintendo_switch_reverse_engineering.
OK - it seems like the first code sample on this document converts a single frequency float into hf
and lf
values. How does this factor in, if the function requires two frequencies?
from nintendo_switch_reverse_engineering.
Ok I understand now. The code is a RFC to understand how to encode a freq to LF OR HF.
To work correctly you need sth like this:
float real_LF = 0.0f;
float real_HF = 0.0f;
//Get user float LF/HF or from somewhere else or hardcoded
real_LF = 160.0f;
real_HF = 320.0f;
// End - code to get LF/HF
// clamp them to acceptable freq
real_LF = clamp( real_LF, 40.875885f, 626.286133f );
real_HF = clamp( real_HF, 81.75177, 1252.572266f );
uint16_t hf = ((uint8_t)round(log2((double)real_HF * 0.01)*32.0)-0x60)*4;
uint8_t lf = (uint8_t)round(log2((double)real_LF * 0.01)*32.0)-0x40;
from nintendo_switch_reverse_engineering.
I may be extremely late on this, but the default values of 320 / 160 Hz and the setting of low and high vibration frequencies seems to all but confirm that the HD Rumble vibration motors are ALPS Electric Haptic Reactors, was this known?
from nintendo_switch_reverse_engineering.
Nope, had no clue.
It's definitely Haptic Reactor. Images, specs and the frequency response graph match.
BTW, I remembered to state something that I always forgot.
As you all saw by now, there are some numbers that are skipped in the High frequencies.
The numbers increment by 4 but actually the in between numbers have specific usage (probably special waves like saw/triangle/etc). If my research goes again that way, I will update with anything I'll find.
EDIT:
The link for the haptic reactor is here.
EDIT2:
The Joy-Con analog sticks.
from nintendo_switch_reverse_engineering.
Looks like the actual part in the Joy-Cons isn't visible on that page - the ....06 has no center push button.
It's probably the ...05 or ...04 or something like that.
from nintendo_switch_reverse_engineering.
True, but the other characteristics probably are the same.
from nintendo_switch_reverse_engineering.
@rei-github
Great work!
I've tested these but couldn't make any sense, because I was using only my hearing and not an oscilloscope.
Is it possible to also record the real frequencies produced so we can update the freq table?
Lastly, I will take a closer look at your findings next Monday and if you want I can do the pull request to include your info.
from nintendo_switch_reverse_engineering.
Yes, but the frequency and the amplitude is almost accurate in my measurement.
oscilloscope is not suitable to measure of amplitude or frequency.
especially for PWM driving motor.
(Haptic actuator is controlled by 250kHz PWM)
Next time when I open joycon, I'll try to measure frequency and amplitude accurately by freq meter or something.
I forgot one thing to note.
the "Phase" of both waves (Hi/Low) always start from "0" and I cannot managed to change.
so I can make "almost saw tooth" wave but cannot change the direction of "SAW" or make "Triangle" wave.
from nintendo_switch_reverse_engineering.
So, if understand correctly and also that they start at 0, the pulses look somewhat like these (I did not use Fourier or anything else, they are by hand):
And pulse 3 has a different phase, correct?
from nintendo_switch_reverse_engineering.
hi, I've made one mistake and forgot one information.
pulse 4 is not the sum of pulse 1+2. it is the time shift of pulse 2.
the time shift of pulse 3 and 4 is 5msec earlier than pulse 1 and 2.
the pulse shape is difficult to describe, so I took some pictures.
from nintendo_switch_reverse_engineering.
the HD motor is driven by PWM of 250kHz.
so to get above waves, I use simple CR low pass filter (2kR, 0.1uF i.e. 800Hz cut off).
because of this filter, pulse shape is not the real one.
from nintendo_switch_reverse_engineering.
Hm, maybe I'm messing something up, but when I try to use pulses, I get a regular vibration, except its frequency shifts down with every (identical) message I send? I can't make sense of it :/
from nintendo_switch_reverse_engineering.
@ThibG make sure you're incrementing the rumble frame timer in the packets you send!
from nintendo_switch_reverse_engineering.
The first byte of the HID output report, referenced as GlobalPacketNumber
in https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md? I'm incrementing it at each packet, but maybe it's out of sync from the beginning somehow? Anyway I don't have this issue when outputing “dual wave” rumble data
from nintendo_switch_reverse_engineering.
What about the packet frequency and hid output report id?
Try with 5ms/10ms/15ms delay after each packet.
Try with ouput report x10
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 2
- 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.