apply non-linear steering curve
This commit is contained in:
@@ -39,6 +39,13 @@ static int mode = G29_MODE_MEDIA;
|
||||
module_param(mode, int, 0444);
|
||||
MODULE_PARM_DESC(mode, "Mapping mode (0=MEDIA)");
|
||||
|
||||
/* Steering curve exponent (100 = linear, 200 = squared, 150 = ^1.5)
|
||||
* Higher values reduce sensitivity at low steering angles.
|
||||
*/
|
||||
static int steer_curve = 200;
|
||||
module_param(steer_curve, int, 0644);
|
||||
MODULE_PARM_DESC(steer_curve, "Steering sensitivity curve (100=linear, 200=squared, default=200)");
|
||||
|
||||
struct g29_keymap_edge {
|
||||
u32 mask;
|
||||
unsigned short keycode;
|
||||
@@ -85,21 +92,59 @@ static void g29_steer_timer_fn(struct timer_list *t) {
|
||||
struct g29_dev *g29 = timer_container_of(g29, t, steer_timer);
|
||||
|
||||
const int rot = le16_to_cpu(g29->last.rot_le);
|
||||
int distance_from_center = abs(rot - WHEEL_CENTER);
|
||||
bool press_key;
|
||||
int distance_to_center = abs(rot - WHEEL_CENTER);
|
||||
int adjusted_distance;
|
||||
|
||||
//pr_info("g29: rot=%d distance_to_center=%d\n", rot, distance_to_center);
|
||||
|
||||
/* Apply non-linear steering curve:
|
||||
* adjusted = (distance / MAX)^(curve/100) * MAX
|
||||
*
|
||||
* For curve=200 (squared): 5% input -> 0.25% output, 50% -> 25%, 100% -> 100%
|
||||
* For curve=150 (^1.5): 5% input -> ~1.1% output, 50% -> ~35%, 100% -> 100%
|
||||
* For curve=100 (linear): 5% input -> 5% output (no change)
|
||||
*
|
||||
* Using integer math: adjusted = (distance^2 / MAX) for curve=200
|
||||
*/
|
||||
if (steer_curve == 100) {
|
||||
/* Linear response - no adjustment */
|
||||
adjusted_distance = distance_to_center;
|
||||
} else if (steer_curve == 200) {
|
||||
/* Squared response - optimized integer calculation */
|
||||
adjusted_distance = (distance_to_center * distance_to_center) / WHEEL_MAX_DIST;
|
||||
} else {
|
||||
/* Generic power curve using normalized values (0-1000 range for precision)
|
||||
* normalized = (distance * 1000) / WHEEL_MAX_DIST
|
||||
* Apply power approximation, then scale back
|
||||
*/
|
||||
int normalized = (distance_to_center * 1000) / WHEEL_MAX_DIST;
|
||||
int powered;
|
||||
|
||||
if (steer_curve == 150) {
|
||||
/* Approximate ^1.5 with (x * sqrt(x)) */
|
||||
int sqrt_norm = int_sqrt(normalized * 1000);
|
||||
powered = (normalized * sqrt_norm) / 1000;
|
||||
} else {
|
||||
/* Fallback: squared for any other value > 100 */
|
||||
powered = (normalized * normalized) / 1000;
|
||||
}
|
||||
|
||||
adjusted_distance = (powered * WHEEL_MAX_DIST) / 1000;
|
||||
}
|
||||
|
||||
/* Phase accumulator approach:
|
||||
* Accumulate the distance on each tick.
|
||||
* Accumulate the adjusted distance on each tick.
|
||||
* When it exceeds the max distance, press the key and wrap.
|
||||
* This gives us a duty cycle of (distance / WHEEL_MAX_DIST).
|
||||
* This gives us a duty cycle of (adjusted_distance / WHEEL_MAX_DIST).
|
||||
*
|
||||
* Examples:
|
||||
* distance = WHEEL_MAX_DIST/2 (50%) -> press every 2nd tick
|
||||
* distance = WHEEL_MAX_DIST (100%) -> press every tick
|
||||
* distance = WHEEL_MAX_DIST/4 (25%) -> press every 4th tick
|
||||
* Examples (with curve=200):
|
||||
* 5% steering -> ~0.25% press rate
|
||||
* 50% steering -> 25% press rate
|
||||
* 100% steering -> 100% press rate (every tick)
|
||||
*/
|
||||
g29->phase_accumulator += distance_from_center;
|
||||
g29->phase_accumulator += adjusted_distance;
|
||||
|
||||
bool press_key;
|
||||
if (g29->phase_accumulator >= WHEEL_MAX_DIST) {
|
||||
g29->phase_accumulator -= WHEEL_MAX_DIST;
|
||||
press_key = true;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define G29_BTN_RED_CW 0x02000000u
|
||||
#define G29_BTN_RED_CCW 0x04000000u
|
||||
#define G29_BTN_RETURN 0x08000000u
|
||||
#define G29_BTN_PS3_LOGO 0xF0000000u
|
||||
|
||||
#define G29_DPAD_MASK 0x0000000Eu
|
||||
#define G29_DPAD_UP 0x00000000u
|
||||
|
||||
@@ -45,7 +45,7 @@ Logitech G29 USB Protocol
|
||||
- `0x02000000` - Red rotation clockwise
|
||||
- `0x04000000` - Red rotation counterclockwise
|
||||
- `0x08000000` - Return
|
||||
- `0xF0000000` - ?
|
||||
- `0xF0000000` - Playstation 3 Logo Button (verify)
|
||||
- `Rot`: Wheel rotation (little-endian). `0x0000` (leftmost) - `0xFFFF` (rightmost).
|
||||
- `Gas`: Gas pedal. `0xFF` (up, default) - `0x00` (down).
|
||||
- `Brk`: Brake pedal. `0xFF` (up, default) - `0x00` (down).
|
||||
|
||||
Reference in New Issue
Block a user