Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request - Force Feedback support #11

Open
Speshl opened this issue Jan 5, 2024 · 3 comments
Open

Feature Request - Force Feedback support #11

Speshl opened this issue Jan 5, 2024 · 3 comments

Comments

@Speshl
Copy link

Speshl commented Jan 5, 2024

Any chances of getting force feedback support added to this repo? Specifically upload effect which is EVIOCSFF (0x80).

I am attempting to add it myself, but I am unfamiliar with IOCTL, so it isn't going great. Getting a bad address error when attempting to make the call.

func ioctlEVIOCSFF(fd uintptr, effect Effect) error {
	code := ioctlMakeCode(ioctlDirWrite, 'E', 0x80, unsafe.Sizeof(effect))
	return doIoctl(fd, code, unsafe.Pointer(&effect))
}
@zonque
Copy link
Contributor

zonque commented Jan 9, 2024

I don't think I have a force feedback device at my disposal to try this. Your code goes in the right direction tho, and what needs to be done is very well in line with existing code. IOW - I think you're close :)

Could you share your definition of the Effect struct?

@Speshl
Copy link
Author

Speshl commented Jan 9, 2024

Sure here is the effect type I have as it exists now. Part of the issue is that in C the FF effect type is defined as a Union and I have not come accross an easy way to mimic that in golang. Attempted to pad out the size of the constant struct to be the proper byte length but that doesn't seem to work.

// Used to build up force feedback effects
type Envelope struct { // 8 bytes
	AttackLength uint16
	AttackLevel  uint16
	FadeLength   uint16
	FadeLevel    uint16
}

type Constant struct { //10 bytes, padded to 24
	Level    int16
	Envelope Envelope

	unused [14]byte
}

type Rumble struct {
	Strong uint16
	Weak   uint16
}

type Periodic struct {
	Waveform     uint16
	Period       uint16
	Magnitude    int16
	Offset       int16
	Phase        uint16
	Envelope     Envelope
	CustomLength uint32
	CustomDate   *int16
}

type Condition struct {
	RightSaturation uint16
	LeftSaturation  uint16
	RightCoeff      int16
	LeftCoeff       int16
	Deadband        uint16
	Center          uint16
}

type Ramp struct {
	Start    int16
	End      int16
	Envelope Envelope
}

type Replay struct { //4 bytes
	Length uint16
	Delay  uint16
}

type Trigger struct { //4 bytes
	Button   uint16
	Interval uint16
}

type EffectType struct {
	Constant Constant //10 bytes, padded to 24
	// Ramp      Ramp //8 bytes
	// Periodic  Periodic //20 bytes
	// Condition [2]Condition //one for each axis 12 (24)
	// Rumble    Rumble //4 bytes
}

type Effect struct { //38 bytes
	Type       uint16
	Id         int16
	Direction  uint16
	Trigger    Trigger
	Replay     Replay
	EffectType EffectType
}

@Speshl
Copy link
Author

Speshl commented Jan 9, 2024

I ended up just forking your repo and doing it with CGO to see if I could get it to work there and it does. Here is my cgo so you can see how to build up the effect to a working constant effect.

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>  // Include for the write() function
#include <linux/input.h>

void Hello(){
    printf("Hello world\n");
}

int upload_effect(uintptr_t fd,  int16_t level, bool effectExists){
    struct ff_effect effect = {};

    effect.type = FF_CONSTANT;
    if(!effectExists){
        effect.id = -1;           // Unique ID for the effect (use -1 for auto-assignment)
    }else{
        effect.id = 0;
    }
   
    effect.direction = 20000;     // Direction of the effect (0 for omni-directional)
    effect.trigger.button = 0; // Button that triggers the effect (0 for no button)
    effect.trigger.interval = 0; // Interval between triggers (0 for continuous)
    effect.replay.length = 0;  // Duration of the effect in milliseconds
    effect.replay.delay = 0;     // Delay before replaying the effect (0 for no delay)

    // Parameters specific to the constant effect
    effect.u.constant.level = level; // Example: Constant force level (signed 16-bit)
    int error = ioctl(fd, EVIOCSFF, &effect);
    if(error != 0){
        return -2;
    }

    struct input_event event;
    struct timeval tval;
    //memset(&event, 0, sizeof(event));
    gettimeofday(&tval, 0);
    event.input_event_usec = tval.tv_usec;
    event.input_event_sec = tval.tv_sec;
    event.type = EV_FF;
    event.code = effect.id;
    event.value = 1;

    if (write(fd, &event, sizeof(event)) != sizeof(event)) {
        return -3;
    }
    return effect.id;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants