AndersMalmgren / FreePIE

Programmable Input Emulator
634 stars 145 forks source link

Add Force Feedback support to vjoy and joystick plugin #48

Open AndersMalmgren opened 9 years ago

AndersMalmgren commented 9 years ago

I have not checked if the C# SDK has the support yet, but here is a demo written in C http://sourceforge.net/p/vjoystick/code/HEAD/tree/branches/Incompatible/ForceFB/apps/FfbMon/FfbMon.cpp

http://vjoystick.sourceforge.net/site/index.php/forum/5-Discussion/393-force-feedback-support?start=20

aubade commented 8 years ago

Is there any chance of this hitting mainline soon? I'd really love to be able to get FFB effects in games that need vjoy for input device merging.

MarijnS95 commented 8 years ago

What a coincidence you just asked that @aubade :)

I've been working on it in the past but there are some nasty problems. But finally I've gotten around to a seemingly working version. https://github.com/MarijnS95/FreePIE_FFB Be aware though, the code:

I might need some help from Anders to get the code working with proper practices, and I should definitely get an FFB wheel to continue development.

aubade commented 8 years ago

Fantastic! I just got the thing to compile (Though, just to warn, I had to delete some $ characters in the code; google indicated they were probably because of failed copy-pastes?), but I'm not sure how to set up a script to do this? If you can give me some example scriptcode I'd be happy to help you test this. (I've got a Logitech Wingman Strike Force 3D atm. Also a very old iForce joystick that won't work past WinXP, but I could still try playing around with that if it's of interest and freepie can still run on XP)

MarijnS95 commented 8 years ago

The dollar signs are a new C# 6.0 String Interpolation feature. Basically string.Format("hello {0}", Name) is equivalent to $"hello {Name}".

This will create a slowly ramping up force (only SlimDX test):

if starting:
    jID = 1;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)

And this will forward FB data (for the moment being only constant force):

if starting:
    vJoy[0].RegisterFFBDevice(joystick[2]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device
AndersMalmgren commented 8 years ago

Nice work on getting something to work! We are still compatible with VS2010 (I think haven't tried in a while :D). Using String Interpolation from VS 2015 will break that, its only a compile time feature and not CLR so you can still run the program on CLR with .NET 4.0 but you will need VS2015 to compile it, haven't decided if we should require our devs to use VS2015 or not just yet.

I looked at the code and its a huge mess right now :D Could you clean in up and I can assist you in getting it more FreePIE like? I do not have a force feedback device either

AndersMalmgren commented 8 years ago

Btw I also see there are alot of changes that are not really changes, do you use the correct tab setting (Ínsert spacec 4)

MarijnS95 commented 8 years ago

I can change the string interpolations to string.Format for the time being (I'm too used to them, totally forgot about older version compatibility). Haven't looked at similar formatting either, so my code still has tab indents. I'll fix that.

Yes it's huge mess, for two main reasons: 1. I haven't been able to test it so I'm not even sure if the current approach works (hence I first want to know that before progressing). And 2: I first want to discuss with you how to proceed. There's multiple different approaches/implementations I can think of, but I've no idea which would suit FreePIE best. However I don't think this (issue tracker) is the best place to do that, I think moving to the forum or direct (voice) chat is the best option? Then I can explain how FFB works in both vJoy and SlimDX, and we can come up with a plan how to implement this in such a neat way as the rest of FreePIE.

However, what I think for now (very basic plan) is to have an easy oneline "automatically forward FFB commands from vJoy device to joystick", and a complete Python implementation so users can modify/forward FFB data however they wish.

aubade commented 8 years ago

Okay, so the first snippet works fine! The automatic nonff-compatability-mode autocentering shuts down on script-run and I feel a stick-forward force slowly intensify. The centering spring returns as soon as I shut the script down.

Unfortunately, the second snippet seems to not work at all; I've tried an external application ( http://www.fs-force.com/support.htm has a program called ForceTest that can send arbitrary effects to arbitrary sticks), as well as combining both scripts.

When the scripts are combined; registering the real stick as vjoy's ffb target, then sending effects to the vjoy stick, the autocentering never disables and I never feel the force. (however, if set to send effects directly to the real stick, it does still work).

I've copied the console output when running this combined script if it's of any help at all.

#code snippet
if starting:
    vJoy[0].RegisterFFBDevice(joystick[1]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device
    jID = 0;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)

Log output: https://dl.dropboxusercontent.com/u/187059/vjoyffb.txt

MarijnS95 commented 8 years ago

It's weird that it doesn't work since it receives all the correct data and sets the settings correctly. The only difference I know of is polar vs cartesian coordinates. I'll modify it and see if that makes a difference.

Log doesn't really help since it's missing the beginning (I should've indented the if(force % 100 == 0): and SetConstantforce below so that it doesn't keep setting that value. However I can see the same log here as well (even tho I don't own an FFB device doesn't mean I can't log what the vJoy device receives, or even forward from vJoy device 0 to 1, however I'm not sure if that causes any problems since all the vJoy stuff is static - the callback triggers for each device rather than per device, have to split that up myself)

Btw can you try one more thing? Move the OperateEffect line to directly below SetConstantForce, something like this:

if starting:
    vJoy[0].RegisterFFBDevice(joystick[1]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device
    jID = 0;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)

Might be that the effect needs to be restarted every time it's changed (at least that's what I've seen when reading force data from another game... It kept sending start operations (even without modifying the magnitude each time))

aubade commented 8 years ago

Sadly, this doesn't seem to be working either; Same joystick-side behavior as above. This time I stopped the program much earlier so as to catch the beginning of the log:

https://dl.dropboxusercontent.com/u/187059/vjoyffb2.txt

Incidentally, I don't know if this is important but every even-numbered time (second, fourth, sixth, etc) I try to run this or my earlier attempted script, it errors out with the error "Unable to create effect: An item with the same key has already been added." on the CreateEffect line, however on odd-numbered run attempts it does run.

aubade commented 8 years ago

Oh blight it all, i'm very sorry; the not-working thing was my fault. I'd ignored a vjoy "please reboot" prompt the other day; after rebooting, my snippet indeed works... but with a stick-back force instead of a stick-forward force. It, however, crashes FreePIE upon script stop. Your revised script makes the force cut in and out

MarijnS95 commented 8 years ago

Wow, you just posted that when I wanted to respond :D So it works with a game or that ForceTest application now?

I know of weird behaviour with effects, dispossing etc, I haven't yet been able to look at it... Multiple packets are sent to dispose every effect separately, and to dispose them altogether. FreePIE disposes the joystick/vJoy devices as well, probably ending up in some problems.

aubade commented 8 years ago

Unfortunately, external applications don't seem to be working atm. The games I've tried (Freespace 2's SCP and IL-2 Sturmovik 1946) don't give any errors, but I don't feel any forces. ForceTest gives an error on device select/reinitialize, at least:

Enumerated Joystick : vJoy Device
Enumerated Joystick : Logitech WingMan Strike Force 3D USB
Supported Effects : 
   - Constant
   - Ramp Force
   - Square Wave
   - Sine Wave
   - Triangle Wave
   - Sawtooth Up Wave
   - Sawtooth Down Wave
   - Damper
   - Inertia
   - Friction
   - CustomForce

Creating effects for vJoy Device
Error creating Spring Effect. Your joystick may not support this effect.  : 
REGDB_E_CLASSNOTREG : 
Class not registered

And gives an error when applying the grooves effect:

Error starting Pavement Groove effect. : 
E_HANDLE : 
Invalid handle

but apart from that, effects are silently discarded.

MarijnS95 commented 8 years ago

The only effect that is currently completely forwarded is Constant(Force).

aubade commented 8 years ago

Okay, then yeah. :( Unfortunately it looks ilke Constant Force from FreePIE is fine, but from ForceTest isn't going through.

MarijnS95 commented 8 years ago

Try FFB inspector: https://www.lfs.net/forum/thread/76818-ForceFeedback-Inspector-(aka-shake-it-baby)

aubade commented 8 years ago

Okay, from FFB inspector it works, if inconsistently; the program seems a bit crashy. I have to unplug the real joystick, start FFB inspector, replug real joystick, start FreePIE, run script, otherwise FFBinspector crashes. Then, sometimes it doesn't actually generate the force when i tell it to start effect, but when it does work, I do feel the forces.

MarijnS95 commented 8 years ago

Cool, finally it 'works' :+1:

I guess that's a problem when scripts stop, things are not correctly disposed, event handler thingies (vJoy exports a method to register a callback method, but no way to get rid of it, so it seems it's held until FreePIE has been restarted). I'll have to look at that later, maybe after I explain to Anders how it works he has some ideas. But at least the basic part is working, which I'm pretty happy about.

aubade commented 8 years ago

Fantastic! feel free to @ me anytime if you need my help.

MarijnS95 commented 8 years ago

I will, though I don't expect to work much on this next week. That is, unless I make some big steps with Anders, as I'm not planning to work a lot only to find out there's a much smarter design/implementation possible. Besides, university (and The Division which is released tuesday) is taking up my time.

AndersMalmgren commented 8 years ago

I created a thread at MTBS that we can use to talk development and clean up of the code.

http://www.mtbs3d.com/phpBB/viewtopic.php?f=139&t=21859

AndersMalmgren commented 8 years ago

I have added some more logging which have found more problems with the forwarding code. Please check the forum, you probably have more knowledge into the Ffb protocol

MarijnS95 commented 8 years ago

I've read the forum, just didn't have any time to test anything last week.

jbinard commented 7 years ago

Any news about the force feedback support ?

AndersMalmgren commented 7 years ago

Hi, im not active on the FreePIE project right now, are working on a VR game full time. But it seems there has been some progress, my suggestion is contacting MarijnS95 in this thread

http://www.mtbs3d.com/phpBB/viewtopic.php?f=139&t=21859&start=40

MarijnS95 commented 7 years ago

@jbinard I'm not that active on it anymore. I was about a month ago (did some huge refactors/cleanups as well as some major breakthoughs packet-wise), but the fact I still don't have an FFB device means it's almost impossible for me to complete it; I have to rely on other people to do the testing/debugging, without proper tools or knowledge about the inner workings. Quick iteration is impossible as I have to send a compiled build out every time I make a tiny change; then request others to test exactly what I want and pray I logged the correct information, which takes days instead of minutes when done locally.

That said though, the forum is the best way to discuss. The version on github/the forum is a bit dated already, mostly missing some minor fixes and debugging stuff everywhere.

erik-smit commented 7 years ago

I've been toying with this for a bit. Here's some notes for any others trying this.

What I've mostly ran into is this line returning an E_INVALIDARG: https://github.com/MarijnS95/FreePIE/blob/Ffb/FreePIE.Core.Plugins/Dx/Device.cs#L194

I've noticed this only happens when using Polar coords. If I change the -1 in 'createEffect' to '0'. I get a wheel turning back and forth with the script below.

if starting:
    jID = 0;#ID of your FFB device
    joystick[jID].createEffect(0, EffectType.ConstantForce, -1, [0, 1])
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 10
else:
    force = -10000

if(force % 100 == 0):
    joystick[jID].setConstantForce(0, force)
    joystick[jID].operateEffect(0, EffectOperation.Start, 0)

Also, sometimes Unable to create new effect: An item with the same key has already been added..

MarijnS95 commented 7 years ago

What I've mostly ran into is this line returning an E_INVALIDARG: https://github.com/MarijnS95/FreePIE/blob/Ffb/FreePIE.Core.Plugins/Dx/Device.cs#L194 I've noticed this only happens when using Polar coords. If I change the -1 in createEffect to '0'. I get a wheel turning back and forth with the script below.

Which is as expected; I 'recently' changed the function signature. In the past the -1 represented the duration (-1 meaning 'infinite'), but now it's a boolean for switching between polar and Cartesian coordinates (-1 evaluates to True, meaning "use polar coordinates"). In that case, the first argument of the array should represent the angle, and the second one must be 0 (which is not the case with the Cartesian parameters [0, 1]). See https://msdn.microsoft.com/en-us/library/windows/desktop/ee417536(v=vs.85).aspx:

Setting up the direction for a polar two-axis effect is only a little more complicated. Set the DIEFF_POLAR flag in dwFlags and set rglDirection to point to an array of two LONGs. The first element in this array is the direction from which you want the effect to come. The second element in the array must be 0.

Anyway, when using Cartesian coordinates, [0, 1] should give you an effect in the positive y-axis, which I do not expect to turn the wheel (as that is x-axis).

Also, sometimes Unable to create new effect: An item with the same key has already been added..

Yes, if you've followed my ramblings on the Spintires forum, it turns out the wheel and/or driver keeps track of these effects even when being disposed. I sent out some fixes for that on the Spintires forum, but never actually committed it until now; see here for the code that tries to avoid creating an effect when it exists. According to Lombra on the ST forum, it doesn't seem to work.

However, when I put "vJoy[0].registerFfbDevice(joystick[dev])" in my script, I seem to be getting some forcefeedback from Spintires (game) passed to my wheel, so yay!

Not sure why this was removed by an edit. False positive?

erik-smit commented 7 years ago

Not sure why this was removed by an edit. False positive?

Correct.

erik-smit commented 7 years ago

Is it supposed to work/do something?

For my purpose, trying to simulate a stickshift with the sequential shifter of my Logitech DF GT for Spintires, the passthrough of registerFfbDevice would be enough.

MarijnS95 commented 7 years ago

Is it supposed to work/do something?

Something, yes. Well, as you might've read on both forums, I've tried quite a lot to get it working, but so far haven't gotten it working. I'm still looking for someone with an FFB wheel and programming skills to do the remaining debugging work, as there's still something preventing FFB from being forwarded.

For my purpose, trying to simulate a stickshift with the sequential shifter of my Logitech DF GT for Spintires, the passthrough of registerFfbDevice would be enough.

Yes, for this scenario registerFfbDevice has been built. However it's not working yet and I'd appreciate it if you could take a look. See the notes in Device.cs for additional details.

erik-smit commented 7 years ago

When trying it now with Spintires, it dies with the following exception:

  HResult=-2146233086
  Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: chunkLength
  ParamName=chunkLength
  Source=mscorlib
  StackTrace:
       at System.Text.StringBuilder.ToString()
       at FreePIE.GUI.Views.Script.Output.InfiniteConsoleTextWriter.WorkerDoWork(Object sender, DoWorkEventArgs e) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.GUI\Views\Script\Output\ConsoleViewModel.cs:line 88
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 

Is my guess correct that this is probably because there's 'too much' output?

Here is the log output: https://gist.github.com/erik-smit/c06a6c01d5d1d7203895c4c41f941eca

MarijnS95 commented 7 years ago

Whoops. That should've not been committed. It was for debugging purposes because there's so many log messages the important start-messages got lost. I reverted it on my branch.

Anyway, there's another E_INVALIDARG at CreateEffect, can you set a breakpoint there and check the parameters?

erik-smit commented 7 years ago

I reverted it on my branch.

On https://github.com/MarijnS95/FreePIE/tree/Ffb ?

What did you revert on your branch? Last change was 5 hours ago.

Anyway, when using Cartesian coordinates, [0, 1] should give you an effect in the positive y-axis, which I do not expect to turn the wheel (as that is x-axis).

https://goo.gl/photos/hqFqAoKDQSfsRfGU8 is what happens with the script I pasted, when I change the polar to cartesian.

Anyway, there's another E_INVALIDARG at CreateEffect, can you set a breakpoint there and check the parameters?

image

Is this what you're looking for?

I must say I don't fully understand how the effectParams passes the 'polar' data. Is this the Magnitude/Size Params?

MarijnS95 commented 7 years ago

On https://github.com/MarijnS95/FreePIE/tree/Ffb ? What did you revert on your branch? Last change was 5 hours ago.

Yes, should be pushed now.

Is this what you're looking for?

Yup. Arguments seem right, at least these are the same used to generate an effect directly from the script.

I must say I don't fully understand how the effectParams passes the 'polar' data. Is this the Magnitude/Size Params?

No, these are passed in through the SetAxes method, might be worth checking the argument there as well (I assume the dirs array doesn't comply to the spec as I pasted earlier. But if it does, it'll probably be [88, 0]).

erik-smit commented 7 years ago

FWIW, the CreateEffect gets called with dirs=[8894,0], which I notice gets passed to effectParams[blockIndex].SetAxes(Axes, dirs);

MarijnS95 commented 7 years ago

FWIW, the CreateEffect gets called with dirs=[8894,0], which I notice gets passed to effectParams[blockIndex].SetAxes(Axes, dirs);

That should be correct (angles have to be multiplied by 100). Maybe the driver is not liking the slight imprecision (that it wants 9000 instead). You could try hardcoding that just for the sake of testing. Otherwise, hardcode cartesian coordinates and an array of [1, 0], see if that solves the issue (if so, I'll add some code to convert polar to Cartesian).

erik-smit commented 7 years ago

You could try hardcoding that just for the sake of testing.

Like so?

+            dirs[0] = 9000;
+            dirs[1] = 0;
+
             effectParams[blockIndex].SetAxes(Axes, dirs);

This still makes E_INVALIDARG.

Otherwise, hardcode cartesian coordinates and an array of [1, 0],

Like so?

            polar = false;
            effectParams[blockIndex] = new EffectParameters()
            {
                Duration = duration,
                Flags = EffectFlags.ObjectIds | (polar ? EffectFlags.Polar : EffectFlags.Cartesian),
                Gain = gain,
                SamplePeriod = samplePeriod,
                StartDelay = startDelay,
                TriggerButton = triggerButton,
                TriggerRepeatInterval = triggerRepeatInterval,
                Envelope = null
            };

            dirs[0] = 1;
            dirs[1] = 0;
            effectParams[blockIndex].SetAxes(Axes, dirs);

This seems to forward some FFB! I can feel it in my wheel!

Here is the log, https://gist.github.com/erik-smit/def36e66e016d9f78884a9c193abbb4f, until the logging breaks with:

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Collection was modified after the enumerator was instantiated.
  Source=System
  StackTrace:
       at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
       at System.Collections.Generic.Queue`1.Enumerator.MoveNext()
       at System.String.Join(String separator, IEnumerable`1 values)
       at FreePIE.GUI.Views.Script.Output.ConsoleTextWriter.WorkerDoWork(Object sender, DoWorkEventArgs e) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.GUI\Views\Script\Output\ConsoleViewModel.cs:line 108
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 
erik-smit commented 7 years ago

For what it's worth, my wheel only has one forcefeedback 'Axis'. I remember reading somewhere that could be relevant to the parameters of SetAxes.

MarijnS95 commented 7 years ago

Both modifications are correct. This tells me there's something wrong with polar coordinates: either it's a driver support thingy; a deprecated/broken feature; or I'm missing something obvious.

This seems to forward some FFB!

\0/ That's really good news :D. Anyway, some?

That crash: logging is being accessed from another thread whilst the logger isn't thread-safe. I did change it from a List to a Queue a while back, but the List itself isn't thread-safe either. This is probably caused by the logging in the OnFfbPacketAvailable codepath, since that runs on another thread.

For what it's worth, my wheel only has one forcefeedback 'Axis'. I remember reading somewhere that could be relevant to the parameters of SetAxes.

Aha, that is important (you've probably read that in the MSDN document here):

Setting up the direction for a single-axis effect is easy because there is nothing to specify. Put the DIEFF_CARTESIAN flag in the dwFlags member of the DIEFFECT structure and set rglDirection to point to a single LONG containing the value 0.

When using polar coordinates, there's a small chance it wants the first array item to be 0, but since a 1D actuator I assume it doesn't accept the polar argument altogether. Also makes sense why cartesian coordinates are accepted: Magnitude ranges from 0-10000 so this direction argument is used to determine "whether it comes from the left or the right" (and I assume that's what you mean with "some FFB"?).

Anyway, I'll write up some code to convert to Cartesian, then you can try again \0/

erik-smit commented 7 years ago

\0/ That's really good news :D. Anyway, some?

I see some ffb action in my wheel when I alt-tab into spintires if I've started FreePIE after switching to the vJoy in Spintires.

If I've started FreePIE before switching from direct-wheel to vjoy in spintires, FreePIE fails with:

----------------------
DataSize: 26, CMD: IOCTL_HID_WRITE_REPORT
1A010101FF00000000FFFF043F00000000000000000000000000
BlockIdx: 1
Device ID: 1
Packet type: Effect
    EffectType: ConstantForce
    Duration: -1
    TriggerRepeatInterval: 0
    SamplePeriod: 0
    Gain: 255
    TriggerBtn (?): -1
    Polar: True
    Angle: 88

Receive->process delay: 3.498ms
Forwarding to 1 device
Creating effect: ConstantForce
This device already has 0 effects created.
Excecption when trying to forward:
    Unable to create new effect: DIERR_NOTEXCLUSIVEACQUIRED & VFW_E_FILTER_ACTIVE & DMO_E_TYPE_NOT_ACCEPTED: The operation cannot be performed unless the device is acquired in DISCL_EXCLUSIVE mode. & This operation cannot be performed because the filter is active. (-2147220987)
       at FreePIE.Core.Plugins.Dx.Device.CreateEffect(Int32 blockIndex, EffectType type) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\Dx\Device.cs:line 231
   at FreePIE.Core.Plugins.Dx.Device.CreateEffect(Int32 blockIndex, EffectType effectType, Boolean polar, Int32[] dirs, Int32 duration, Int32 gain, Int32 samplePeriod, Int32 startDelay, Int32 triggerButton, Int32 triggerRepeatInterval) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\Dx\Device.cs:line 143
   at FreePIE.Core.Plugins.Dx.Device.SetEffectParams(EffectReportPacket er) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\Dx\Device.cs:line 120
   at FreePIE.Core.Plugins.VJoy.PacketMapper.<>c.<SetupDefaultMap>b__5_0(Device d, EffectReportPacket p) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\VJoy\PacketMapper.cs:line 25
   at FreePIE.Core.Plugins.VJoy.AsyncPacketData`1.Call(IList`1 registeredDevices) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\VJoy\PacketAction.cs:line 65

This is probably caused by the logging in the OnFfbPacketAvailable codepath, since that runs on another thread.

I've commented out https://github.com/MarijnS95/FreePIE/blob/Ffb/FreePIE.Core.Plugins/VJoy/VJoyFFBWrap.cs#L65

And it seems like it takes a much longer time to crash now. :)

Still crashes though.

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Collection was modified after the enumerator was instantiated.
  Source=System
  StackTrace:
       at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
       at System.Collections.Generic.Queue`1.Enumerator.MoveNext()
       at System.String.Join(String separator, IEnumerable`1 values)
       at FreePIE.GUI.Views.Script.Output.ConsoleTextWriter.WorkerDoWork(Object sender, DoWorkEventArgs e) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.GUI\Views\Script\Output\ConsoleViewModel.cs:line 108
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 

Anyway, I'll write up some code to convert to Cartesian, then you can try again \0/

\o/ I'll leave you to it.

Just one curiosity. Why is this necessary? Why wouldn't Spintires send something that my LGDT can grok?

MarijnS95 commented 7 years ago

I see some ffb action in my wheel when I alt-tab into spintires if I've started FreePIE after switching to the vJoy in Spintires. If I've started FreePIE before switching from direct-wheel to vjoy in spintires, FreePIE fails with:

That makes sense: FreePIE needs to have exclusive access to the DFGT in order to send FFB commands; if the game still has that exclusive access FreePIE will fail.

I've commented out https://github.com/MarijnS95/FreePIE/blob/Ffb/FreePIE.Core.Plugins/VJoy/VJoyFFBWrap.cs#L65 And it seems like it takes a much longer time to crash now. :) Still crashes though.

Hmm, that's the only line I can find. I could add some code to dump a stacktrace (easiest is to just throw an Exception ;)) when the WriteLine method is called from a thread that's not the main thread. I'll see if I can get that on a separate branch just for testing purposes.

Just one curiosity. Why is this necessary? Why wouldn't Spintires send something that my LGDT can grok?

Because Spintires isn't talking to your DFGT, it's talking to a virtual vJoy device, which does not have the same hardware configuration. Hence why all this forwarding (and conversion) is needed in the first place.

MarijnS95 commented 7 years ago

Finally got time to write the conversion function, it's on the Ffb branch now.

You can find the log thread check on this branch.

erik-smit commented 7 years ago

Because Spintires isn't talking to your DFGT, it's talking to a virtual vJoy device, which does not have the same hardware configuration. Hence why all this forwarding (and conversion) is needed in the first place.

Ahh, the virtual vJoy maybe exports a bunch more axis, making Spintires send different effectParameters than to the DFGT?

And it's probably not easy/sane to try to get FreePIE to feed vJoy the parameters of the physical stick?

MarijnS95 commented 7 years ago

Ahh, the virtual vJoy maybe exports a bunch more axis, making Spintires send different effectParameters than to the DFGT?

Kindof, yes. I don't think the effectParameters are that much different, probably only the direction/SetAxis thingy.

And it's probably not easy/sane to try to get FreePIE to feed vJoy the parameters of the physical stick?

Nope. Nothing in the vJoy settings application (only finetuning of available effects). (As expected,) neither in the 'API'.

Also, does it work better with the 'forced' conversion?

erik-smit commented 7 years ago

You can find the log thread check on this branch.

System.Exception was unhandled by user code
  HResult=-2146233088
  Message=Logging is *not* thread-safe!
  Source=FreePIE
  StackTrace:
       at FreePIE.GUI.Views.Script.Output.ConsoleTextWriter.WriteLine(String value) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.GUI\Views\Script\Output\ConsoleViewModel.cs:line 126
       at System.IO.TextWriter.WriteLine(String format, Object arg0, Object arg1)
       at System.IO.TextWriter.SyncTextWriter.WriteLine(String format, Object arg0, Object arg1)
       at System.Console.WriteLine(String format, Object arg0, Object arg1)
       at FreePIE.Core.Plugins.VJoy.VJoyGlobalHolder..ctor(UInt32 index) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\VJoy\VJoyGlobalHolder.cs:line 46
       at FreePIE.Core.Plugins.VJoyPlugin.Create(UInt32 index) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\VJoyPlugin.cs:line 38
       at FreePIE.Core.Plugins.Globals.GlobalIndexer`2.get_Item(TIndex index) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.Core.Plugins\Globals\GlobalIndexer.cs:line 30
       at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
       at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
       at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
  InnerException: 

Finally got time to write the conversion function, it's on the Ffb branch now.

!!!!

It seems to be doing stuff! But only the first time after I start a FreePIE session. When I alt-tab out and in of Spintires again, I lose the FFB until I stop/start FreePIE again. And no more logging, makes it hard to see what's happening.

But yay, progress!

Anything else you want me to try/do/etc.?

MarijnS95 commented 7 years ago

Hmm, the constructor of the console writer is ran from a different thread, not particularly helpful. I pushed another approach to that branch.

It seems to be doing stuff! But only the first time after I start a FreePIE session. When I alt-tab out and in of Spintires again, I lose the FFB until I stop/start FreePIE again.

That's probably due to all the disposing etc that doesn't seem to happen properly. Spintires releases the joystick and effects on alt+tab, which is 'forwarded' to the DFGT as well. As a temporary solution, you can try commenting out the corresponding line. I'll have to research this behaviour though; Spintires recreates the effects once tabbed back in which should get everything back to a working state...

And no more logging, makes it hard to see what's happening.

Wut? Commenting out line 65 in VjoyFFBWrap.cs shouldn't cause all the logging to disappear. Actually all the important information is printed here.

erik-smit commented 7 years ago

Wut? Commenting out line 65 in VjoyFFBWrap.cs shouldn't cause all the logging to disappear. Actually all the important information is printed here.

Ahh, I had done my testing on the logging branch and changed 'https://github.com/MarijnS95/FreePIE/blob/7763a59baebf9b28a0128a770182a8f540dfa400/FreePIE.GUI/Views/Script/Output/ConsoleViewModel.cs#L126' to 'return' to make it 'working'.

Hmm, the constructor of the console writer is ran from a different thread, not particularly helpful. I pushed another approach to that branch.

This is probably why I was no longer getting logging output then.

I'll test it again now.

erik-smit commented 7 years ago

The logging branch still exceptions.

Collection was modified after the enumerator was instantiated. is the threading unsafe stuff, right?

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Collection was modified after the enumerator was instantiated.
  Source=System
  StackTrace:
       at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
       at System.Collections.Generic.Queue`1.Enumerator.MoveNext()
       at System.String.Join(String separator, IEnumerable`1 values)
       at FreePIE.GUI.Views.Script.Output.ConsoleTextWriter.WorkerDoWork(Object sender, DoWorkEventArgs e) in C:\Users\zoiah\Documents\FreePIE\FreePIE\FreePIE.GUI\Views\Script\Output\ConsoleViewModel.cs:line 109
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 
MarijnS95 commented 7 years ago

The logging branch still exceptions.

Yes, intentionally. I didn't want to just lock it; instead figure out why it was accessed from multiple threads in the first place (and whether my FFB code was to blame).

~Interesting. If it's not triggering the other exception, it means logging all happens from the same thread, and that FreePIE itself uses a different thread to generate the text for display.~ This has probably never been found because in most cases there's not more than 1000 lines of debugging output. (However strictly speaking Add/Enqueue modify a collection as well, but since these are appended on the end I guess the enumerator is able to handle that).

Regarding the strikethrough: It must've been late yesterday. ConsoleWriters use a BackgroundWorker right there in ConsoleViewModel.cs, don't know how I missed that 😳. I added some locking to synchronize access (on the Ffb branch), it should work without crashing now.