Skip to content

Commit

Permalink
hid-xpadneo: Scale rumble magnitudes correctly
Browse files Browse the repository at this point in the history
According to `hid-microsoft.c`, the device supports magnitudes in the
range of 0..100.

This commit scales the magnitudes correctly from 0..65535 to 0..100 and
also uses a finer scale for the pre-calculated cosine table to have
more than 4 steps on each trigger.

Additionally, it considerably reduces the strength of the connection
notification rumble. The controller no longer tends to hop down the
table.

I don't have any specs of this but sending too high values may affect
the stability of the firmware thus this may reduce connection losses
observed in some issue reports.

This also removes the over-use of blank lines: It confuses git during
rebase as it allows splitting logical self-contained hunks into
seemingly unrelated blocks on too many opportunities.

Closes: atar-axis#154
Affects: atar-axis#149
Maybe-related: atar-axis#171
Maybe-related: atar-axis#122
Signed-off-by: Kai Krakow <[email protected]>
  • Loading branch information
kakra committed May 4, 2020
1 parent ba7ae0f commit ce95e08
Showing 1 changed file with 21 additions and 31 deletions.
52 changes: 21 additions & 31 deletions hid-xpadneo/src/hid-xpadneo.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,13 @@ static int xpadneo_ff_play(struct input_dev *dev, void *data,
*/

struct ff_report ff_pck;
u16 weak, strong, direction, max, max_damped;
u32 weak, strong, direction, max, max_damped, max_unscaled;
u8 mag_main_right, mag_main_left, mag_trigger_right, mag_trigger_left;
u8 ff_active;

const int fractions_milli[]
= {1000, 962, 854, 691, 500, 309, 146, 38, 0};
const int proportions_idx_max = 8;
const int fractions_percent[]
= {100, 96, 85, 69, 50, 31, 15, 4, 0, 4, 15, 31, 50, 69, 85, 96, 100};
const int proportions_idx_max = 16;
u8 index_left, index_right;
int fraction_TL, fraction_TR;
u8 trigger_rumble_damping_nonzero;
Expand Down Expand Up @@ -269,59 +269,49 @@ static int xpadneo_ff_play(struct input_dev *dev, void *data,
strong, weak, direction);

/* calculate the physical magnitudes */
mag_main_right = (u8)((weak & 0xFF00) >> 8); /* u16 to u8 */
mag_main_left = (u8)((strong & 0xFF00) >> 8); /* u16 to u8 */

mag_main_right = (u8)((weak * 100) / 0xFFFF); /* scale from 16 bit to 0..100 */
mag_main_left = (u8)((strong * 100) / 0xFFFF); /* scale from 16 bit to 0..100 */

/* get the proportions from a precalculated cosine table
* calculation goes like:
* cosine(a) * 1000 = {1000, 924, 707, 383, 0, -383, -707, -924, -1000}
* fractions_milli(a) = (1000 + (cosine * 1000)) / 2
* cosine(a) * 100 = {100, 96, 85, 69, 50, 31, 15, 4, 0, 4, 15, 31, 50, 69, 85, 96, 100}
* fractions_percent(a) = round(50 + (cosine * 50))
*/

fraction_TL = 0;
fraction_TR = 0;

if (direction >= DIRECTION_LEFT && direction <= DIRECTION_RIGHT) {
index_left = (direction - DIRECTION_LEFT) >> 12;
index_left = (direction - DIRECTION_LEFT) >> 11;
index_right = proportions_idx_max - index_left;

fraction_TL = fractions_milli[index_left];
fraction_TR = fractions_milli[index_right];
fraction_TL = fractions_percent[index_left];
fraction_TR = fractions_percent[index_right];
}

/* we want to keep the rumbling at the triggers below the maximum
* of the weak and strong main rumble
*/
* of the weak and strong main rumble
*/
max = mag_main_right > mag_main_left ? mag_main_right : mag_main_left;
max_unscaled = weak > strong ? weak : strong;

/* the user can change the damping at runtime, hence check the range */
trigger_rumble_damping_nonzero
= param_trigger_rumble_damping == 0 ? 1 : param_trigger_rumble_damping;

max_damped = max / trigger_rumble_damping_nonzero;

mag_trigger_left = (u8)((max_damped * fraction_TL) / 1000);
mag_trigger_right = (u8)((max_damped * fraction_TR) / 1000);

max_damped = max_unscaled / trigger_rumble_damping_nonzero;
mag_trigger_left = (u8)((max_damped * fraction_TL) / 0xFFFF);
mag_trigger_right = (u8)((max_damped * fraction_TR) / 0xFFFF);

ff_active = FF_ENABLE_ALL;

if (param_disable_ff & PARAM_DISABLE_FF_TRIGGER)
ff_active &= ~(FF_ENABLE_LEFT_TRIGGER | FF_ENABLE_RIGHT_TRIGGER);

if (param_disable_ff & PARAM_DISABLE_FF_MAIN)
ff_active &= ~(FF_ENABLE_LEFT | FF_ENABLE_RIGHT);


create_ff_pck(
&ff_pck, 0x03,
ff_active,
mag_trigger_left, mag_trigger_right,
mag_main_left, mag_main_right,
0);


hid_dbg_lvl(DBG_LVL_FEW, hdev,
"active: %#04x, max: %#04x, prop_left: %#04x, prop_right: %#04x, left trigger: %#04x, right: %#04x\n",
ff_active,
Expand Down Expand Up @@ -356,10 +346,10 @@ static int xpadneo_initDevice(struct hid_device *hdev)
/* 'HELLO' FROM THE OTHER SIDE */
if (!param_disable_ff) {
ff_pck.report_id = 0x03;
ff_pck.ff.magnitude_right = 0x80;
ff_pck.ff.magnitude_left = 0x40;
ff_pck.ff.magnitude_right_trigger = 0x20;
ff_pck.ff.magnitude_left_trigger = 0x20;
ff_pck.ff.magnitude_right = 40;
ff_pck.ff.magnitude_left = 20;
ff_pck.ff.magnitude_right_trigger = 10;
ff_pck.ff.magnitude_left_trigger = 10;
ff_pck.ff.duration = 33;

ff_pck.ff.enable_actuators = FF_ENABLE_RIGHT;
Expand Down

0 comments on commit ce95e08

Please sign in to comment.