Giter Club home page Giter Club logo

Comments (31)

rei-github avatar rei-github commented on July 21, 2024 2

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.

CTCaer avatar CTCaer commented on July 21, 2024 1

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:
Alt
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.

facekapow avatar facekapow commented on July 21, 2024 1

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.

facekapow avatar facekapow commented on July 21, 2024 1

Sorry, val is supposed to be encoded. I'll edit that.

from nintendo_switch_reverse_engineering.

riking avatar riking commented on July 21, 2024

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.

fossephate avatar fossephate commented on July 21, 2024

@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.

shinyquagsire23 avatar shinyquagsire23 commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

The HD-Rumble is well known now. Can we close this?

from nintendo_switch_reverse_engineering.

facekapow avatar facekapow commented on July 21, 2024

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.

facekapow avatar facekapow commented on July 21, 2024

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.

wormyrocks avatar wormyrocks commented on July 21, 2024

where does val come from in this alg?

from nintendo_switch_reverse_engineering.

wormyrocks avatar wormyrocks commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

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.

wormyrocks avatar wormyrocks commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

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.

wormyrocks avatar wormyrocks commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

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.

wormyrocks avatar wormyrocks commented on July 21, 2024

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?

Discussion here.

from nintendo_switch_reverse_engineering.

CTCaer avatar CTCaer commented on July 21, 2024

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.

riking avatar riking commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

True, but the other characteristics probably are the same.

from nintendo_switch_reverse_engineering.

CTCaer avatar CTCaer commented on July 21, 2024

@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.

rei-github avatar rei-github commented on July 21, 2024

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.
saw tooth wave

from nintendo_switch_reverse_engineering.

CTCaer avatar CTCaer commented on July 21, 2024

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.

rei-github avatar rei-github commented on July 21, 2024

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
pulse1

pulse 2
pulse2

pulse 3
pulse3

pulse 4
pulse4

pulse 1+2
pulse1 2

pulse 1+3
pulse1 3

pulse 1+4
pulse1 4

pulse 2+3
pulse2 3

pulse 2+4
pulse2 4

pulse 3+4
pulse3 4

pulse 1+2+3
pulse1 2 3

pulse 1+2+4
pulse1 2 4

pulse 1+3+4
pulse1 3 4

pulse 2+3+4
pulse2 3 4

pulse 1+2+3+4
pulse1 2 3 4

from nintendo_switch_reverse_engineering.

rei-github avatar rei-github commented on July 21, 2024

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.

dsc_0019

from nintendo_switch_reverse_engineering.

ClearlyClaire avatar ClearlyClaire commented on July 21, 2024

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.

riking avatar riking commented on July 21, 2024

@ThibG make sure you're incrementing the rumble frame timer in the packets you send!

from nintendo_switch_reverse_engineering.

ClearlyClaire avatar ClearlyClaire commented on July 21, 2024

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.

CTCaer avatar CTCaer commented on July 21, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.