Open a7a00 opened 7 years ago
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.
@lyra833 could you post what you sent to the JoyCons / their responses? I haven't been able to get any rumble events to trigger
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
The HD-Rumble is well known now. Can we close this?
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
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.
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. 😄
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];
where does val
come from in this alg?
Sorry, val
is supposed to be encoded
. I'll edit that.
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
?
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 )
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.
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 | HFu16 & 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..
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.
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?
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;
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?
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.
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.
True, but the other characteristics probably are the same.
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.
@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.
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.
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?
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.
pulse 1
pulse 2
pulse 3
pulse 4
pulse 1+2
pulse 1+3
pulse 1+4
pulse 2+3
pulse 2+4
pulse 3+4
pulse 1+2+3
pulse 1+2+4
pulse 1+3+4
pulse 2+3+4
pulse 1+2+3+4
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.
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 :/
@ThibG make sure you're incrementing the rumble frame timer in the packets you send!
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
What about the packet frequency and hid output report id? Try with 5ms/10ms/15ms delay after each packet. Try with ouput report x10
I've been wrangling around with the Joy-Con and think I've figured out how the rumble data is sent over, starting from byte 13 in the packet sent from the Switch. (It doesn't look like standard HID...)
Byte 13 is a constant,
0x10
. It's probably an identifier, as it's always0xf
for all pings not containing rumble data. Byte 14 looks like some sort of timekeeper in the event of the packets colliding; it starts at0xa
, increments with every ping sent until0xf
, then loops back around to0x0
,0x1
, etc. Changing either of these bits doesn't trigger any rumble at all. There are then 8 bits, 6 of which seem to correspond to the 6 faces of the Joy-Con; but my drivers started crapping out before I could dope out the last 2. The first of the 8 (Byte 15) seems to be some sort of global intensity modifier; as changing it seemed to jolt the whole thing more or less, so that leaves 6 faces, one global modifier, and ?????.I've managed to trigger some rumble events, but my laptop drivers are suddenly refusing to play nice with the Joy-Cons. I'm not sure if it's hardware failure or something to do with manipulating this data, but I'd love to have some fresh eyes verify it. I verified it against @DekuNukem's BotW data and it seems to check out with respects to which bits change when during the bomb rumble. (I would love to try it with this, because it would let us isolate which bits correspond to which edge of the Joy-Con.)
Once someone else verifies, we can add it to the README?
Oh, and as a clarification because my Bluetooth has been hell, they're sending the same data over BT as they are over serial, right? The only thing that's different is the clock speed?