/// <summary> /// Called when vJoy has a new FFB packet. /// WARNING This is called from a thread pool managed by windows. /// The thread itself is created and managed by vJoyInterface.dll. /// Do not overload it, else you will me missing FFB packets from /// third party application. /// </summary> /// <param name="ffbDataPtr"></param> /// <param name="userData"></param> public void FfbReceiverFunction(IntPtr data, object userdata) { // Packet Header //copy ffb packet to managed structure InternalFfbPacket packet = (InternalFfbPacket)Marshal.PtrToStructure(data, typeof(InternalFfbPacket)); /////// Packet Device ID, and Type Block Index (if exists) #region Packet Device ID, and Type Block Index #if DUMP_FFB_FRAME if (vJoyManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { DumpFrame(data); } #endif uint DeviceID = 0, BlockIndex = 0; FFBPType Type = new FFBPType(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DeviceID(data, ref DeviceID)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " > Device ID: {0}", DeviceID); } } // Effect block index only used when simultaneous effects should be done by // underlying hardware, which is not the case for a single motor driving wheel if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffectBlockIndex(data, ref BlockIndex)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " > Effect Block Index: {0}", BlockIndex); } } if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Type(data, ref Type)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { if (!PacketType2Str(Type, out var TypeStr)) { LogFormat(LogLevels.DEBUG, " > Packet Type: {0}", Type); } else { LogFormat(LogLevels.DEBUG, " > Packet Type: {0}", TypeStr); } } switch (Type) { case FFBPType.PT_POOLREP: if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " > Pool report handled by driver side"); } break; case FFBPType.PT_BLKLDREP: if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " > Block Load report handled by driver side"); } break; case FFBPType.PT_BLKFRREP: FFBManager.FreeEffect(BlockIndex); // Update PID Joystick.FfbReadPID(DeviceID, ref PIDBlock); if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " > Block Free effect id {0}", PIDBlock.NextFreeEID); } break; } } #endregion #region PID Device Control FFB_CTRL Control = new FFB_CTRL(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevCtrl(data, ref Control) && DevCtrl2Str(Control, out var CtrlStr)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> PID Device Control: {0}", CtrlStr); } switch (Control) { case FFB_CTRL.CTRL_DEVRST: // Update PID data to get the resetted values from driver side Joystick.FfbReadPID(DeviceID, ref PIDBlock); // device reset FFBManager.DevReset(); break; case FFB_CTRL.CTRL_ENACT: FFBManager.DevEnable(); break; case FFB_CTRL.CTRL_DISACT: FFBManager.DevDisable(); break; case FFB_CTRL.CTRL_STOPALL: FFBManager.StopAllEffects(); break; } } #endregion #region Create new effect FFBEType EffectType = new FFBEType(); uint NewBlockIndex = 0; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_CreateNewEffect(data, ref EffectType, ref NewBlockIndex)) { FFBManager.CreateNewEffect(NewBlockIndex); // Update PID Joystick.FfbReadPID(Id, ref PIDBlock); if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { if (EffectType2Str(EffectType, out var TypeStr)) { LogFormat(LogLevels.DEBUG, " >> Effect Type: {0}", TypeStr); } else { LogFormat(LogLevels.DEBUG, " >> Effect Type: Unknown({0})", EffectType); } LogFormat(LogLevels.DEBUG, " >> New Effect ID: {0}", NewBlockIndex); if (NewBlockIndex != PIDBlock.PIDBlockLoad.EffectBlockIndex) { LogFormat(LogLevels.DEBUG, "!!! BUG NewBlockIndex=" + NewBlockIndex + " <> pid=" + ((int)PIDBlock.PIDBlockLoad.EffectBlockIndex)); } LogFormat(LogLevels.DEBUG, " >> LoadStatus {0}", PIDBlock.PIDBlockLoad.LoadStatus); } } #endregion #region Condition vJoy.FFB_EFF_COND Condition = new vJoy.FFB_EFF_COND(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Cond(data, ref Condition)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { if (Condition.isY) { LogFormat(LogLevels.DEBUG, " >> Y Axis"); } else { LogFormat(LogLevels.DEBUG, " >> X Axis"); } LogFormat(LogLevels.DEBUG, " >> Center Point Offset: {0}", TwosCompWord2Int(Condition.CenterPointOffset)); LogFormat(LogLevels.DEBUG, " >> Positive Coefficient: {0}", TwosCompWord2Int(Condition.PosCoeff)); LogFormat(LogLevels.DEBUG, " >> Negative Coefficient: {0}", TwosCompWord2Int(Condition.NegCoeff)); LogFormat(LogLevels.DEBUG, " >> Positive Saturation: {0}", Condition.PosSatur); LogFormat(LogLevels.DEBUG, " >> Negative Saturation: {0}", Condition.NegSatur); LogFormat(LogLevels.DEBUG, " >> Dead Band: {0}", Condition.DeadBand); } // Skip all processing if Y axis (single axis for wheel FFB!) if (Condition.isY) { // Leave early! return; } FFBManager.SetLimitsParams(BlockIndex, TwosCompWord2Int(Condition.CenterPointOffset) * Scale_FFB_to_u, Condition.DeadBand * Scale_FFB_to_u, TwosCompWord2Int(Condition.PosCoeff) * Scale_FFB_to_u, TwosCompWord2Int(Condition.NegCoeff) * Scale_FFB_to_u, Condition.PosSatur * Scale_FFB_to_u, -Condition.NegSatur * Scale_FFB_to_u); } #endregion #region Effect Report vJoy.FFB_EFF_REPORT Effect = new vJoy.FFB_EFF_REPORT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Report(data, ref Effect)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { if (!EffectType2Str(Effect.EffectType, out var TypeStr)) { LogFormat(LogLevels.DEBUG, " >> Effect Report: {0} {1}", (int)Effect.EffectType, Effect.EffectType.ToString()); } else { LogFormat(LogLevels.DEBUG, " >> Effect Report: {0}", TypeStr); } LogFormat(LogLevels.DEBUG, " >> AxisEnabledDirection: {0}", (ushort)Effect.AxesEnabledDirection); } if (Effect.Polar) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Direction: {0} deg ({1})", Polar2Deg(Effect.Direction), Effect.Direction); } FFBManager.SetDirection(BlockIndex, Polar2Deg(Effect.Direction)); } else { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> X Direction: {0}", Effect.DirX); LogFormat(LogLevels.DEBUG, " >> Y Direction: {0}", Effect.DirY); } FFBManager.SetDirection(BlockIndex, Effect.DirX); } if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { if (Effect.Duration == 0xFFFF) { LogFormat(LogLevels.DEBUG, " >> Duration: Infinit"); } else { LogFormat(LogLevels.DEBUG, " >> Duration: {0} MilliSec", (int)(Effect.Duration)); } if (Effect.TrigerRpt == 0xFFFF) { LogFormat(LogLevels.DEBUG, " >> Trigger Repeat: Infinit"); } else { LogFormat(LogLevels.DEBUG, " >> Trigger Repeat: {0}", (int)(Effect.TrigerRpt)); } if (Effect.SamplePrd == 0xFFFF) { LogFormat(LogLevels.DEBUG, " >> Sample Period: Infinit"); } else { LogFormat(LogLevels.DEBUG, " >> Sample Period: {0}", (int)(Effect.SamplePrd)); } if (Effect.StartDelay == 0xFFFF) { LogFormat(LogLevels.DEBUG, " >> Start Delay: max "); } else { LogFormat(LogLevels.DEBUG, " >> Start Delay: {0}", (int)(Effect.StartDelay)); } LogFormat(LogLevels.DEBUG, " >> Gain: {0}%%", Byte2Percent(Effect.Gain)); } if (Effect.Duration == 65535) { FFBManager.SetDuration(BlockIndex, -1.0); } else { FFBManager.SetDuration(BlockIndex, Effect.Duration); } if (Effect.StartDelay == 65535) { FFBManager.SetStartDelay(BlockIndex, 0); } else { FFBManager.SetStartDelay(BlockIndex, Effect.StartDelay); } FFBManager.SetEffectGain(BlockIndex, Byte2Percent(Effect.Gain) * 0.01); switch (Effect.EffectType) { case FFBEType.ET_CONST: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.CONSTANT_TORQUE); break; case FFBEType.ET_RAMP: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.RAMP); break; case FFBEType.ET_INRT: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.INERTIA); break; case FFBEType.ET_SPRNG: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.SPRING); break; case FFBEType.ET_DMPR: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.DAMPER); break; case FFBEType.ET_FRCTN: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.FRICTION); break; // Periodic case FFBEType.ET_SQR: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.SQUARE); break; case FFBEType.ET_SINE: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.SINE); break; case FFBEType.ET_TRNGL: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.TRIANGLE); break; case FFBEType.ET_STUP: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.SAWTOOTHUP); break; case FFBEType.ET_STDN: FFBManager.SetEffect(BlockIndex, FFBManager.EffectTypes.SAWTOOTHDOWN); break; } } #endregion #region Effect Operation vJoy.FFB_EFF_OP Operation = new vJoy.FFB_EFF_OP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffOp(data, ref Operation) && EffectOpStr(Operation.EffectOp, out var EffOpStr)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Effect Operation: {0}", EffOpStr); if (Operation.LoopCount == 0xFF) { LogFormat(LogLevels.DEBUG, " >> Loop until stopped"); } else { LogFormat(LogLevels.DEBUG, " >> Loop {0} times", (int)(Operation.LoopCount)); } } switch (Operation.EffectOp) { case FFBOP.EFF_START: // Start the effect identified by the Effect Handle. FFBManager.StartEffect(BlockIndex, (int)(Operation.LoopCount)); break; case FFBOP.EFF_STOP: // Stop the effect identified by the Effect Handle. FFBManager.StopEffect(BlockIndex); break; case FFBOP.EFF_SOLO: // Start the effect identified by the Effect Handle and stop all other effects. FFBManager.StartEffect(BlockIndex, 1); break; } } #endregion #region Global Device Gain byte Gain = 0; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevGain(data, ref Gain)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Global Device Gain: {0}", Byte2Percent(Gain)); } FFBManager.SetDeviceGain(Byte2Percent(Gain) * 0.01); } #endregion #region Envelope vJoy.FFB_EFF_ENVLP Envelope = new vJoy.FFB_EFF_ENVLP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Envlp(data, ref Envelope)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Attack Level: {0}", Envelope.AttackLevel); LogFormat(LogLevels.DEBUG, " >> Fade Level: {0}", Envelope.FadeLevel); LogFormat(LogLevels.DEBUG, " >> Attack Time: {0}", (int)(Envelope.AttackTime)); LogFormat(LogLevels.DEBUG, " >> Fade Time: {0}", (int)(Envelope.FadeTime)); } FFBManager.SetEnveloppeParams(BlockIndex, Envelope.AttackTime, Envelope.AttackLevel, Envelope.FadeTime, Envelope.FadeLevel); } #endregion #region Periodic vJoy.FFB_EFF_PERIOD EffPrd = new vJoy.FFB_EFF_PERIOD(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Period(data, ref EffPrd)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Magnitude: {0}", EffPrd.Magnitude); LogFormat(LogLevels.DEBUG, " >> Offset: {0}", TwosCompWord2Int(EffPrd.Offset)); LogFormat(LogLevels.DEBUG, " >> Phase: {0}", EffPrd.Phase * 3600 / 255); LogFormat(LogLevels.DEBUG, " >> Period: {0}", (int)(EffPrd.Period)); } FFBManager.SetPeriodicParams(BlockIndex, (double)EffPrd.Magnitude * Scale_FFB_to_u, TwosCompWord2Int(EffPrd.Offset) * Scale_FFB_to_u, EffPrd.Phase * 0.01, EffPrd.Period); } #endregion #region Ramp Effect vJoy.FFB_EFF_RAMP RampEffect = new vJoy.FFB_EFF_RAMP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Ramp(data, ref RampEffect)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Ramp Start: {0}", TwosCompWord2Int(RampEffect.Start)); LogFormat(LogLevels.DEBUG, " >> Ramp End: {0}", TwosCompWord2Int(RampEffect.End)); } FFBManager.SetRampParams(BlockIndex, RampEffect.Start * Scale_FFB_to_u, RampEffect.End * Scale_FFB_to_u); } #endregion #region Constant Effect vJoy.FFB_EFF_CONSTANT CstEffect = new vJoy.FFB_EFF_CONSTANT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Constant(data, ref CstEffect)) { if (BFFManager.Config.Application.VerbosevJoyFFBReceiverDumpFrames) { LogFormat(LogLevels.DEBUG, " >> Block Index: {0}", TwosCompWord2Int(CstEffect.EffectBlockIndex)); LogFormat(LogLevels.DEBUG, " >> Magnitude: {0}", TwosCompWord2Int(CstEffect.Magnitude)); } FFBManager.SetConstantTorqueEffect(BlockIndex, (double)CstEffect.Magnitude * Scale_FFB_to_u); } #endregion }
void FfbRecieved(IntPtr data, IntPtr userData) { int devId = 0; FFBPType someT = new FFBPType(); if (vjoy.Ffb_h_DeviceID(data, ref devId) == 0 && vjoy.Ffb_h_Type(data, ref someT) == 0) { if (someT == FFBPType.PT_EFOPREP) { vJoy.FFB_EFF_OP a = new vJoy.FFB_EFF_OP(); vjoy.Ffb_h_EffOp(data, ref a); if (devId == 1) { if (a.EffectOp == FFBOP.EFF_STOP) { Interlocked.Exchange(ref gcn1Ffb, 0); } else { Interlocked.Exchange(ref gcn1Ffb, gcn1FfbDur * a.LoopCount); } } else if (devId == 2) { if (a.EffectOp == FFBOP.EFF_STOP) { Interlocked.Exchange(ref gcn2Ffb, 0); } else { Interlocked.Exchange(ref gcn2Ffb, gcn2FfbDur * a.LoopCount); } } else if (devId == 3) { if (a.EffectOp == FFBOP.EFF_STOP) { Interlocked.Exchange(ref gcn3Ffb, 0); } else { Interlocked.Exchange(ref gcn3Ffb, gcn3FfbDur * a.LoopCount); } } else if (devId == 4) { if (a.EffectOp == FFBOP.EFF_STOP) { Interlocked.Exchange(ref gcn4Ffb, 0); } else { Interlocked.Exchange(ref gcn4Ffb, gcn4FfbDur * a.LoopCount); } } } else if (someT == FFBPType.PT_EFFREP) { vJoy.FFB_EFF_REPORT b = new vJoy.FFB_EFF_REPORT(); vjoy.Ffb_h_Eff_Report(data, ref b); if (devId == 1) { gcn1FfbDur = b.Duration; if (b.Duration == 0xFFFF) { gcn1FfbInf = true; } else { gcn1FfbInf = false; } } else if (devId == 2) { gcn2FfbDur = b.Duration; if (b.Duration == 0xFFFF) { gcn2FfbInf = true; } else { gcn2FfbInf = false; } } else if (devId == 3) { gcn3FfbDur = b.Duration; if (b.Duration == 0xFFFF) { gcn3FfbInf = true; } else { gcn3FfbInf = false; } } else if (devId == 4) { gcn4FfbDur = b.Duration; if (b.Duration == 0xFFFF) { gcn4FfbInf = true; } else { gcn4FfbInf = false; } } } else if (someT == FFBPType.PT_CTRLREP) { FFB_CTRL ctrl = new FFB_CTRL(); vjoy.Ffb_h_DevCtrl(data, ref ctrl); if (ctrl == FFB_CTRL.CTRL_DEVRST || ctrl == FFB_CTRL.CTRL_STOPALL) { if (devId == 1) { Interlocked.Exchange(ref gcn1Ffb, 0); } else if (devId == 2) { Interlocked.Exchange(ref gcn2Ffb, 0); } else if (devId == 3) { Interlocked.Exchange(ref gcn3Ffb, 0); } else if (devId == 4) { Interlocked.Exchange(ref gcn4Ffb, 0); } } //else // Log(null, new LogEventArgs("Unimplemented CTRL: " + ctrl)); } else if (someT == FFBPType.PT_PRIDREP) { vJoy.FFB_EFF_PERIOD a = new vJoy.FFB_EFF_PERIOD(); if (vjoy.Ffb_h_Eff_Period(data, ref a) != 0) { Log(null, new LogEventArgs("Ffb_h_Eff_Period error")); } else { if (devId == 1) { gcn1FfbActive = (a.Period > 0 && a.Magnitude > 0); } else if (devId == 2) { gcn2FfbActive = (a.Period > 0 && a.Magnitude > 0); } else if (devId == 3) { gcn3FfbActive = (a.Period > 0 && a.Magnitude > 0); } else if (devId == 4) { gcn4FfbActive = (a.Period > 0 && a.Magnitude > 0); } } //Log(null, new LogEventArgs(" " + a.Magnitude + " " + a.Period + " " + a.Phase)); } else if (someT == FFBPType.PT_GAINREP) { byte gain = new byte(); if (vjoy.Ffb_h_DevGain(data, ref gain) != 0) { Log(null, new LogEventArgs("Ffb_h_DevGain error")); } } else if (someT == FFBPType.PT_NEWEFREP) { FFBEType a = new FFBEType(); if (vjoy.Ffb_h_EffNew(data, ref a) != 0) { Log(null, new LogEventArgs("Ffb_h_EffNew error")); } } else if (someT == FFBPType.PT_BLKFRREP || someT == FFBPType.PT_BLKLDREP) { int index = 0; if (vjoy.Ffb_h_EBI(data, ref index) != 0) { Log(null, new LogEventArgs("Ffb_h_EBI error")); } } else if (someT == FFBPType.PT_CONSTREP) { vJoy.FFB_EFF_CONSTANT a = new vJoy.FFB_EFF_CONSTANT(); if (vjoy.Ffb_h_Eff_Constant(data, ref a) != 0) { Log(null, new LogEventArgs("Ffb_h_Eff_Constant error")); } else { if (devId == 1) { gcn1FfbActive = (a.Magnitude != 0); } else if (devId == 2) { gcn2FfbActive = (a.Magnitude != 0); } else if (devId == 3) { gcn3FfbActive = (a.Magnitude != 0); } else if (devId == 4) { gcn4FfbActive = (a.Magnitude != 0); } } } else if (someT == FFBPType.PT_RAMPREP) { vJoy.FFB_EFF_RAMP a = new vJoy.FFB_EFF_RAMP(); if (vjoy.Ffb_h_Eff_Ramp(data, ref a) != 0) { Log(null, new LogEventArgs("Ffb_h_Eff_Ramp error")); } else { if (devId == 1) { gcn1FfbActive = (a.Start != 0 || a.End != 0); } else if (devId == 2) { gcn2FfbActive = (a.Start != 0 || a.End != 0); } else if (devId == 3) { gcn3FfbActive = (a.Start != 0 || a.End != 0); } else if (devId == 4) { gcn4FfbActive = (a.Start != 0 || a.End != 0); } } } //else // Log(null, new LogEventArgs("Unimplemented force feedback command: " + someT)); } }
private static void OnEffect(IntPtr data, IntPtr userData) { int id = 0; FFBPType type = 0; int DSize = 0; Byte[] arr = new Byte[20]; UInt32 wType = 0; IntPtr bytes = IntPtr.Zero; string TypeStr = ""; object obj = null; TesterForm form = null; // Converting user data from pointer to object if (userData != IntPtr.Zero) { // Convert userData from pointer to object GCHandle handle2 = (GCHandle)userData; obj = handle2.Target as object; form = obj as TesterForm; } // Get FFB packet raw data var result = joystick.Ffb_h_Packet(data, ref wType, ref DSize, ref arr); dlg.FfbTextBox_Write(String.Format("\r\n\r\n ============= FFB Packet size Size {0} =============", DSize + 8)); // Get the ID of the device that this DDB packet refers to result = joystick.Ffb_h_DeviceID(data, ref id); dlg.FfbTextBox_Write(String.Format("\r\n > Device ID: {0}", id)); // Get the type of the packet result = joystick.Ffb_h_Type(data, ref type); if (result == 0) { bool ok = PacketType2Str(type, ref TypeStr); if (!ok) { dlg.FfbTextBox_Write(String.Format("\r\n > Packet Type: {0}", type)); } else { dlg.FfbTextBox_Write(String.Format("\r\n > Packet Type: {0}", TypeStr)); } } ; // Get the index of the effect block (Always 1) int iBlock = 0; result = joystick.Ffb_h_EBI(data, ref iBlock); if (result == 0) { dlg.FfbTextBox_Write(String.Format("\r\n > Effect Block Index: {0}", iBlock)); } // TODO: Add constant magnitude #region Effect Report // Effect Report vJoy.FFB_EFF_REPORT Effect = new vJoy.FFB_EFF_REPORT(); result = joystick.Ffb_h_Eff_Report(data, ref Effect); if (result == 0) { ///// This is an Effect Block // Effect type if (!EffectType2Str(Effect.EffectType, ref TypeStr)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Effect Report: {0}", Effect.EffectType)); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Effect Report: {0}", TypeStr)); } // Effect Direction if (Effect.Polar) { dlg.FfbTextBox_Write(String.Format("\r\n >> Direction: {0} deg ({1:D2})", Polar2Deg(Effect.Direction), Effect.Direction)); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> X Direction: {0:X2}", Effect.DirX)); dlg.FfbTextBox_Write(String.Format("\r\n >> Y Direction: {0:X2}", Effect.DirY)); }; // Duration of the effect if (Effect.Duration == 0xFFFF) { dlg.FfbTextBox_Write(String.Format("\r\n >> Duration: Infinit")); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Duration: {0} MilliSec", (int)(Effect.Duration))); } // Trigger Repeat if (Effect.TrigerRpt == 0xFFFF) { dlg.FfbTextBox_Write(String.Format("\r\n >> Trigger Repeat: Infinit")); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Trigger Repeat: {0}", (int)(Effect.TrigerRpt))); } // Sample Period if (Effect.SamplePrd == 0xFFFF) { dlg.FfbTextBox_Write(String.Format("\r\n >> Sample Period: Infinit")); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Sample Period: {0}", (int)(Effect.SamplePrd))); } // Gain dlg.FfbTextBox_Write(String.Format("\r\n >> Gain: {0}%", Byte2Percent(Effect.Gain))); } ; #endregion Effect Report #region PID Device Control // Device Control (Global controls such as Device Reset, Device Pause ..... FFB_CTRL Control = FFB_CTRL.CTRL_STOPALL; string CtrlStr = ""; if ((0 == joystick.Ffb_h_DevCtrl(data, ref Control)) && DevCtrl2Str(Control, ref CtrlStr)) { dlg.FfbTextBox_Write(String.Format("\r\n >> PID Device Control: {0}", CtrlStr)); } #endregion #region Effect Operation vJoy.FFB_EFF_OP Operation = new vJoy.FFB_EFF_OP(); string EffOpStr = ""; if (0 == joystick.Ffb_h_EffOp(data, ref Operation) && EffectOpStr(Operation.EffectOp, ref EffOpStr)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Effect Operation: {0}", EffOpStr)); if (Operation.LoopCount == 0xFF) { dlg.FfbTextBox_Write(String.Format("\r\n >> Loop until stopped")); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Loop {0} times", (int)(Operation.LoopCount))); } } ; #endregion #region Global Device Gain Byte Gain = 0; if (0 == joystick.Ffb_h_DevGain(data, ref Gain)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Global Device Gain: {0}", Byte2Percent(Gain))); } #endregion #region Condition vJoy.FFB_EFF_COND Condition = new vJoy.FFB_EFF_COND(); if (0 == joystick.Ffb_h_Eff_Cond(data, ref Condition)) { if (Condition.isY) { dlg.FfbTextBox_Write(String.Format("\r\n >> Y Axis")); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> X Axis")); } dlg.FfbTextBox_Write(String.Format("\r\n >> Center Point Offset: {0}", Condition.CenterPointOffset)); dlg.FfbTextBox_Write(String.Format("\r\n >> Positive Coefficient: {0}", Condition.PosCoeff)); dlg.FfbTextBox_Write(String.Format("\r\n >> Negative Coefficient: {0}", Condition.NegCoeff)); dlg.FfbTextBox_Write(String.Format("\r\n >> Positive Saturation: {0}", Condition.PosSatur)); dlg.FfbTextBox_Write(String.Format("\r\n >> Negative Saturation: {0}", Condition.NegSatur)); dlg.FfbTextBox_Write(String.Format("\r\n >> Dead Band: {0}", Condition.DeadBand)); } #endregion #region Envelope vJoy.FFB_EFF_ENVLP Envelope = new vJoy.FFB_EFF_ENVLP(); if (0 == joystick.Ffb_h_Eff_Envlp(data, ref Envelope)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Attack Level: {0}", Envelope.AttackLevel)); dlg.FfbTextBox_Write(String.Format("\r\n >> Fade Level: {0}", Envelope.FadeLevel)); dlg.FfbTextBox_Write(String.Format("\r\n >> Attack Time: {0}", (int)(Envelope.AttackTime))); dlg.FfbTextBox_Write(String.Format("\r\n >> Fade Time: {0}", (int)(Envelope.FadeTime))); } ; #endregion #region Periodic vJoy.FFB_EFF_PERIOD EffPrd = new vJoy.FFB_EFF_PERIOD(); if (0 == joystick.Ffb_h_Eff_Period(data, ref EffPrd)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Magnitude: {0}", EffPrd.Magnitude)); dlg.FfbTextBox_Write(String.Format("\r\n >> Offset: {0}", EffPrd.Offset)); dlg.FfbTextBox_Write(String.Format("\r\n >> Phase: {0}", EffPrd.Phase)); dlg.FfbTextBox_Write(String.Format("\r\n >> Period: {0}", (int)(EffPrd.Period))); } ; #endregion #region Effect Type FFBEType EffectType = FFBEType.ET_NONE; if (0 == joystick.Ffb_h_EffNew(data, ref EffectType)) { if (EffectType2Str(EffectType, ref TypeStr)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Effect Type: {0}", TypeStr)); } else { dlg.FfbTextBox_Write(String.Format("\r\n >> Effect Type: Unknown")); } } #endregion #region Ramp Effect vJoy.FFB_EFF_RAMP RampEffect = new vJoy.FFB_EFF_RAMP(); if (0 == joystick.Ffb_h_Eff_Ramp(data, ref RampEffect)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Ramp Start: {0}", RampEffect.Start)); dlg.FfbTextBox_Write(String.Format("\r\n >> Ramp End: {0}", RampEffect.End)); } ; #endregion #region Constant Effect vJoy.FFB_EFF_CONSTANT ConstantEffect = new vJoy.FFB_EFF_CONSTANT(); if (0 == joystick.Ffb_h_Eff_Constant(data, ref ConstantEffect)) { dlg.FfbTextBox_Write(String.Format("\r\n >> Constant Magnitude: {0}", ConstantEffect.Magnitude)); } ; #endregion dlg.FfbTextBox_Write(String.Format("\r\n ==============================================\r\n")); }
public static VirtualFFBPacket ProcessFFBPacket(IntPtr data, object userData) { VirtualFFBPacket FFBPacket = new VirtualFFBPacket(); if (joystick.Ffb_h_Type(data, ref FFBPacket._FFBPType) == ERROR_SUCCESS) { joystick.Ffb_h_DeviceID(data, ref FFBPacket.ID); switch (FFBPacket._FFBPType) { case FFBPType.PT_EFFREP: // Effect Report (also named EFFECT_CONST) if (joystick.Ffb_h_Eff_Report(data, ref FFBPacket.FFB_EFF_REPORT) == ERROR_SUCCESS) { FFBPacket.BlockIndex = FFBPacket.FFB_EFF_REPORT.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Effect Report"); logger.Trace(FFBPacket.GenerateEffectInfo()); } break; case FFBPType.PT_ENVREP: // Envelope Report if (joystick.Ffb_h_Eff_Envlp(data, ref FFBPacket.FFB_EFF_ENVLP) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_ENVLP.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Envelope Report"); } break; case FFBPType.PT_CONDREP: // Condition Report !! if (joystick.Ffb_h_Eff_Cond(data, ref FFBPacket.FFB_EFF_COND) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_COND.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Condition Report"); StringBuilder dat = new StringBuilder(); dat.AppendFormat($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Condition Report\n"); dat.AppendFormat($"\t EBI={FFBPacket.FFB_EFF_COND.EffectBlockIndex}\n"); dat.AppendFormat($"\t Center={FFBPacket.FFB_EFF_COND.CenterPointOffset}\n"); dat.AppendFormat($"\t DeadBand={FFBPacket.FFB_EFF_COND.DeadBand}\n"); dat.AppendFormat($"\t isY={FFBPacket.FFB_EFF_COND.isY}\n"); dat.AppendFormat($"\t NegCoeff={FFBPacket.FFB_EFF_COND.NegCoeff}\n"); dat.AppendFormat($"\t NegSatur={FFBPacket.FFB_EFF_COND.NegSatur}\n"); dat.AppendFormat($"\t PosCoeff={FFBPacket.FFB_EFF_COND.PosCoeff}\n"); dat.AppendFormat($"\t PosSatur={FFBPacket.FFB_EFF_COND.PosSatur}"); logger.Trace(dat); } break; case FFBPType.PT_PRIDREP: // Periodic Report if (joystick.Ffb_h_Eff_Period(data, ref FFBPacket.FFB_EFF_PERIOD) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_PERIOD.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Periodic Report"); StringBuilder dat = new StringBuilder(); dat.AppendFormat($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Periodic Report\n"); dat.AppendFormat($"\t EBI={FFBPacket.FFB_EFF_PERIOD.EffectBlockIndex}\n"); dat.AppendFormat($"\t Magnitude={FFBPacket.FFB_EFF_PERIOD.Magnitude}\n"); dat.AppendFormat($"\t Offset={FFBPacket.FFB_EFF_PERIOD.Offset}\n"); dat.AppendFormat($"\t Period={FFBPacket.FFB_EFF_PERIOD.Period}\n"); dat.AppendFormat($"\t Phase={FFBPacket.FFB_EFF_PERIOD.Phase}"); logger.Trace(dat); } break; case FFBPType.PT_CONSTREP: // Constant Force Report if (joystick.Ffb_h_Eff_Constant(data, ref FFBPacket.FFB_EFF_CONSTANT) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_CONSTANT.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Constant Force Report, magnitude={FFBPacket.FFB_EFF_CONSTANT.Magnitude}"); } break; case FFBPType.PT_RAMPREP: // Ramp Force Report if (joystick.Ffb_h_Eff_Ramp(data, ref FFBPacket.FFB_EFF_RAMP) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_RAMP.EffectBlockIndex; logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Ramp Force Report"); StringBuilder dat = new StringBuilder(); dat.AppendFormat($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Ramp Force Report\n"); dat.AppendFormat($"\t EBI={FFBPacket.FFB_EFF_RAMP.EffectBlockIndex}\n"); dat.AppendFormat($"\t Start={FFBPacket.FFB_EFF_RAMP.Start}\n"); dat.AppendFormat($"\t End={FFBPacket.FFB_EFF_RAMP.End}\n"); logger.Trace(dat); } break; case FFBPType.PT_CSTMREP: // Custom Force Data Report logger.Debug($"Custom Force Data Report"); break; case FFBPType.PT_SMPLREP: // Download Force Sample joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Download Force Sample"); break; case FFBPType.PT_EFOPREP: // Effect Operation Report if (joystick.Ffb_h_EffOp(data, ref FFBPacket.FFB_EFF_OP) == ERROR_SUCCESS) { FFBPacket.BlockIndex = (uint)FFBPacket.FFB_EFF_OP.EffectBlockIndex; logger.Trace($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Effect Operation Report loop={FFBPacket.FFB_EFF_OP.LoopCount} action={FFBPacket.FFB_EFF_OP.EffectOp}"); } break; case FFBPType.PT_BLKFRREP: // PID Block Free Report joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] PID Block Free Report"); break; case FFBPType.PT_CTRLREP: // PID Device Control joystick.Ffb_h_DevCtrl(data, ref FFBPacket.FFB_CTRL); logger.Debug($"[{FFBPacket.ID}][_] PID Device Control {FFBPacket.FFB_CTRL}"); break; case FFBPType.PT_GAINREP: // Device Gain Report joystick.Ffb_h_DevGain(data, ref FFBPacket.Gain); logger.Debug($"[{FFBPacket.ID}][_] Device Gain Report={FFBPacket.Gain}"); break; case FFBPType.PT_SETCREP: // Set Custom Force Report joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Set Custom Force Report"); break; case FFBPType.PT_NEWEFREP: // Create New Effect Report !! joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); joystick.Ffb_h_CreateNewEffect(data, ref FFBPacket.FFBENextType, ref FFBPacket.NextBlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Create New Effect Report, next={FFBPacket.FFBENextType}[nextEBI={FFBPacket.NextBlockIndex}]"); break; case FFBPType.PT_BLKLDREP: // Block Load Report joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] Block Load Report"); break; case FFBPType.PT_POOLREP: // PID Pool Report joystick.Ffb_h_EBI(data, ref FFBPacket.BlockIndex); logger.Debug($"[{FFBPacket.ID}][EBI={FFBPacket.BlockIndex}] PID Pool Report"); break; } // FFBDataReceived?.Invoke(FFBPacket); return(FFBPacket); } return(null); }
/// <summary> /// Called when vJoy has a new FFB packet. /// WARNING This is called from a thread pool managed by windows. /// The thread itself is created and managed by vJoyInterface.dll. /// Do not overload it, else you will me missing FFB packets from /// third party application. /// </summary> /// <param name="ffbDataPtr"></param> /// <param name="userData"></param> public void FfbFunction1(IntPtr data, object userdata) { // Packet Header //copy ffb packet to managed structure InternalFfbPacket packet = (InternalFfbPacket)Marshal.PtrToStructure(data, typeof(InternalFfbPacket)); // Packet Header LogFormat("============= FFB Packet ============="); /////// Packet Device ID, and Type Block Index (if exists) #region Packet Device ID, and Type Block Index uint DeviceID = 0, BlockIndex = 0; FFBPType Type = new FFBPType(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DeviceID(data, ref DeviceID)) { LogFormat(" > Device ID: {0}", DeviceID); } // Effect block index only used when simultaneous effects should be done by // underlying hardware, which is not the case for a single motor driving wheel if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffectBlockIndex(data, ref BlockIndex)) { LogFormat(" > Effect Block Index: {0}", BlockIndex); } if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Type(data, ref Type)) { if (!PacketType2Str(Type, out var TypeStr)) { LogFormat(" > Packet Type: {0}", Type); } else { LogFormat(" > Packet Type: {0}", TypeStr); } switch (Type) { case FFBPType.PT_POOLREP: LogFormat(" > Pool report handled by driver side"); break; case FFBPType.PT_BLKLDREP: LogFormat(" > Block Load report handled by driver side"); break; case FFBPType.PT_BLKFRREP: //FFBManager.FreeEffect(BlockIndex); // Update PID Joystick.FfbReadPID(DeviceID, ref PIDBlock); LogFormat(" > Block Free effect id {0}", PIDBlock.NextFreeEID); break; } } #endregion #region PID Device Control FFB_CTRL Control = new FFB_CTRL(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevCtrl(data, ref Control) && DevCtrl2Str(Control, out var CtrlStr)) { LogFormat(" >> PID Device Control: {0}", CtrlStr); switch (Control) { case FFB_CTRL.CTRL_DEVRST: // Update PID data to get the resetted values from driver side Joystick.FfbReadPID(DeviceID, ref PIDBlock); // device reset break; case FFB_CTRL.CTRL_ENACT: break; case FFB_CTRL.CTRL_DISACT: break; case FFB_CTRL.CTRL_STOPALL: break; } } #endregion #region Create new effect FFBEType EffectType = new FFBEType(); uint NewBlockIndex = 0; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_CreateNewEffect(data, ref EffectType, ref NewBlockIndex)) { // Create new effect // Update PID Joystick.FfbReadPID(Id, ref PIDBlock); if (EffectType2Str(EffectType, out var TypeStr)) { LogFormat(" >> Effect Type: {0}", TypeStr); } else { LogFormat(" >> Effect Type: Unknown({0})", EffectType); } LogFormat(" >> New Effect ID: {0}", NewBlockIndex); if (NewBlockIndex != PIDBlock.PIDBlockLoad.EffectBlockIndex) { LogFormat("!!! BUG NewBlockIndex=" + NewBlockIndex + " <> pid=" + ((int)PIDBlock.PIDBlockLoad.EffectBlockIndex)); } LogFormat(" >> LoadStatus {0}", PIDBlock.PIDBlockLoad.LoadStatus); } #endregion #region Condition vJoy.FFB_EFF_COND Condition = new vJoy.FFB_EFF_COND(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Cond(data, ref Condition)) { if (Condition.isY) { LogFormat(" >> Y Axis"); } else { LogFormat(" >> X Axis"); } LogFormat(" >> Center Point Offset: {0}", TwosCompWord2Int(Condition.CenterPointOffset)); LogFormat(" >> Positive Coefficient: {0}", TwosCompWord2Int(Condition.PosCoeff)); LogFormat(" >> Negative Coefficient: {0}", TwosCompWord2Int(Condition.NegCoeff)); LogFormat(" >> Positive Saturation: {0}", Condition.PosSatur); LogFormat(" >> Negative Saturation: {0}", Condition.NegSatur); LogFormat(" >> Dead Band: {0}", Condition.DeadBand); } #endregion #region Effect Report vJoy.FFB_EFF_REPORT Effect = new vJoy.FFB_EFF_REPORT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Report(data, ref Effect)) { if (!EffectType2Str(Effect.EffectType, out var TypeStr)) { LogFormat(" >> Effect Report: {0} {1}", (int)Effect.EffectType, Effect.EffectType.ToString()); } else { LogFormat(" >> Effect Report: {0}", TypeStr); } LogFormat(" >> AxisEnabledDirection: {0}", (ushort)Effect.AxesEnabledDirection); if (Effect.Polar) { LogFormat(" >> Direction: {0} deg ({1})", Polar2Deg(Effect.Direction), Effect.Direction); } else { LogFormat(" >> X Direction: {0}", Effect.DirX); LogFormat(" >> Y Direction: {0}", Effect.DirY); } if (Effect.Duration == 0xFFFF) { LogFormat(" >> Duration: Infinit"); } else { LogFormat(" >> Duration: {0} MilliSec", (int)(Effect.Duration)); } if (Effect.TrigerRpt == 0xFFFF) { LogFormat(" >> Trigger Repeat: Infinit"); } else { LogFormat(" >> Trigger Repeat: {0}", (int)(Effect.TrigerRpt)); } if (Effect.SamplePrd == 0xFFFF) { LogFormat(" >> Sample Period: Infinit"); } else { LogFormat(" >> Sample Period: {0}", (int)(Effect.SamplePrd)); } if (Effect.StartDelay == 0xFFFF) { LogFormat(" >> Start Delay: max "); } else { LogFormat(" >> Start Delay: {0}", (int)(Effect.StartDelay)); } LogFormat(" >> Gain: {0}%%", Byte2Percent(Effect.Gain)); } #endregion #region Effect Operation vJoy.FFB_EFF_OP Operation = new vJoy.FFB_EFF_OP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffOp(data, ref Operation) && EffectOpStr(Operation.EffectOp, out var EffOpStr)) { LogFormat(" >> Effect Operation: {0}", EffOpStr); if (Operation.LoopCount == 0xFF) { LogFormat(" >> Loop until stopped"); } else { LogFormat(" >> Loop {0} times", (int)(Operation.LoopCount)); } switch (Operation.EffectOp) { case FFBOP.EFF_START: // Start the effect identified by the Effect Handle. break; case FFBOP.EFF_STOP: // Stop the effect identified by the Effect Handle. break; case FFBOP.EFF_SOLO: // Start the effect identified by the Effect Handle and stop all other effects. break; } } #endregion #region Global Device Gain byte Gain = 0; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevGain(data, ref Gain)) { LogFormat(" >> Global Device Gain: {0}", Byte2Percent(Gain)); } #endregion #region Envelope vJoy.FFB_EFF_ENVLP Envelope = new vJoy.FFB_EFF_ENVLP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Envlp(data, ref Envelope)) { LogFormat(" >> Attack Level: {0}", Envelope.AttackLevel); LogFormat(" >> Fade Level: {0}", Envelope.FadeLevel); LogFormat(" >> Attack Time: {0}", (int)(Envelope.AttackTime)); LogFormat(" >> Fade Time: {0}", (int)(Envelope.FadeTime)); } #endregion #region Periodic vJoy.FFB_EFF_PERIOD EffPrd = new vJoy.FFB_EFF_PERIOD(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Period(data, ref EffPrd)) { LogFormat(" >> Magnitude: {0}", EffPrd.Magnitude); LogFormat(" >> Offset: {0}", TwosCompWord2Int(EffPrd.Offset)); LogFormat(" >> Phase: {0}", EffPrd.Phase * 3600 / 255); LogFormat(" >> Period: {0}", (int)(EffPrd.Period)); } #endregion #region Ramp Effect vJoy.FFB_EFF_RAMP RampEffect = new vJoy.FFB_EFF_RAMP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Ramp(data, ref RampEffect)) { LogFormat(" >> Ramp Start: {0}", TwosCompWord2Int(RampEffect.Start)); LogFormat(" >> Ramp End: {0}", TwosCompWord2Int(RampEffect.End)); } #endregion #region Constant Effect vJoy.FFB_EFF_CONSTANT CstEffect = new vJoy.FFB_EFF_CONSTANT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Constant(data, ref CstEffect)) { LogFormat(" >> Block Index: {0}", TwosCompWord2Int(CstEffect.EffectBlockIndex)); LogFormat(" >> Magnitude: {0}", TwosCompWord2Int(CstEffect.Magnitude)); } #endregion DumpFrame(data); LogFormat("======================================"); }
//private EffectBlock effectBlockNew = null; //Block to be loaded private void func_OnEffectObj(IntPtr data, object userData) { Trace.WriteLine(""); //Trace.WriteLine(vJoy_Extra.FfbGetEffect()); const int ERROR_SUCCESS = 0; Trace.WriteLine(string.Format("Got FFB Packet")); int id = -1; FFBPType type = (FFBPType)0; Int32 effectBlockIndex = -1; if (joystick.Ffb_h_DeviceID(data, ref id) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable to read DevID"); return; } if (joystick.Ffb_h_Type(data, ref type) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable to read FFB type"); return; } Trace.WriteLine(type.ToString()); if (joystick.Ffb_h_EBI(data, ref effectBlockIndex) != ERROR_SUCCESS) { effectBlockIndex = -1; } FFBDevice srcDevice = devices[id - 1]; //Read Based on Type switch (type) { case FFBPType.PT_EFFREP: vJoy.FFB_EFF_REPORT effectParam = new vJoy.FFB_EFF_REPORT(); if (joystick.Ffb_h_Eff_Report(data, ref effectParam) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Effect Param"); return; } Trace.WriteLine(string.Format("Got Effect Param on EBI: {0}", effectParam.EffectBlockIndex)); //Trace.WriteLine(String.Format("EffectType: {0}", effectParam.EffectType.ToString())); //Trace.WriteLine(String.Format("Duration : {0}", effectParam.Duration)); //Trace.WriteLine(String.Format("TrigerRpt : {0}", effectParam.TrigerRpt)); //Trace.WriteLine(String.Format("SamplePrd : {0}", effectParam.SamplePrd)); //Trace.WriteLine(String.Format("Gain : {0}", effectParam.Gain)); //Trace.WriteLine(String.Format("TrigerBtn : {0}", effectParam.TrigerBtn)); //Trace.WriteLine(String.Format("Polar : {0}", effectParam.Polar)); //Trace.WriteLine(String.Format("Dir1 : {0}", effectParam.DirX)); //Trace.WriteLine(String.Format("Dir2 : {0}", effectParam.DirY)); byte[] rawP = new byte[0]; int len = 0; uint transfertype = 0; joystick.Ffb_h_Packet(data, ref transfertype, ref len, ref rawP); Trace.WriteLine(string.Format("TypeSpecificBlockOffset1 : {0}", BitConverter.ToUInt16(rawP, len - 4))); Trace.WriteLine(string.Format("TypeSpecificBlockOffset2 : {0}", BitConverter.ToUInt16(rawP, len - 2))); srcDevice.EffectBlocks[(byte)effectBlockIndex].ffbHeader = effectParam; break; case FFBPType.PT_ENVREP: vJoy.FFB_EFF_ENVLP envEffect = new vJoy.FFB_EFF_ENVLP(); if (joystick.Ffb_h_Eff_Envlp(data, ref envEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Envelope Effect"); return; } srcDevice.EffectBlocks[(byte)effectBlockIndex].SecondaryEffectData(envEffect); Trace.WriteLine(string.Format("Got Envelope Effect on EBI: {0}", envEffect.EffectBlockIndex)); //Trace.WriteLine(String.Format("Start : {0}", envEffect.AttackLevel)); //Trace.WriteLine(String.Format("STime : {0}", envEffect.AttackTime)); //Trace.WriteLine(String.Format("End : {0}", envEffect.FadeLevel)); //Trace.WriteLine(String.Format("ETime : {0}", envEffect.FadeTime)); break; case FFBPType.PT_CONDREP: vJoy.FFB_EFF_COND condEffect = new vJoy.FFB_EFF_COND(); if (joystick.Ffb_h_Eff_Cond(data, ref condEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Conditional Effect"); return; } Trace.WriteLine(string.Format("Got Conditional Effect on EBI (Not Supported): {0}", effectBlockIndex)); break; case FFBPType.PT_PRIDREP: vJoy.FFB_EFF_PERIOD perEffect = new vJoy.FFB_EFF_PERIOD(); if (joystick.Ffb_h_Eff_Period(data, ref perEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Periodic Effect"); return; } Trace.WriteLine(string.Format("Got Periodic Effect on EBI: {0}", perEffect.EffectBlockIndex)); //Trace.WriteLine(String.Format("Magnitude : {0}", perEffect.Magnitude)); //Trace.WriteLine(String.Format("Offset : {0}", perEffect.Offset)); //Trace.WriteLine(String.Format("Phase : {0}", perEffect.Phase)); //Trace.WriteLine(String.Format("Period : {0}", perEffect.Period)); srcDevice.EffectBlocks[(byte)effectBlockIndex].PrimaryEffectData(perEffect); break; case FFBPType.PT_CONSTREP: vJoy.FFB_EFF_CONSTANT constEffect = new vJoy.FFB_EFF_CONSTANT(); if (joystick.Ffb_h_Eff_Constant(data, ref constEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Constant Effect"); return; } Trace.WriteLine(string.Format("Got Const Effect on EBI : {0}", constEffect.EffectBlockIndex)); //Trace.WriteLine(String.Format("Magnitude : {0}", constEffect.Magnitude)); srcDevice.EffectBlocks[(byte)effectBlockIndex].PrimaryEffectData(constEffect); break; case FFBPType.PT_RAMPREP: vJoy.FFB_EFF_RAMP rampEffect = new vJoy.FFB_EFF_RAMP(); if (joystick.Ffb_h_Eff_Ramp(data, ref rampEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Ramp Effect"); return; } Trace.WriteLine(string.Format("Got Ramp Effect on EBI (Not Tested): {0}", rampEffect.EffectBlockIndex)); //Trace.WriteLine(String.Format("Start : {0}", rampEffect.Start)); //Trace.WriteLine(String.Format("End : {0}", rampEffect.End)); srcDevice.EffectBlocks[(byte)effectBlockIndex].PrimaryEffectData(rampEffect); break; case FFBPType.PT_CSTMREP: Trace.WriteLine("Error: Unkown command"); break; case FFBPType.PT_SMPLREP: Trace.WriteLine("Error: Unkown command"); break; case FFBPType.PT_EFOPREP: vJoy.FFB_EFF_OP effect_OP = new vJoy.FFB_EFF_OP(); if (joystick.Ffb_h_EffOp(data, ref effect_OP) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Effect OP"); return; } Trace.WriteLine(string.Format("Effect Command : {0}, Loops : {1}, EBI : {2} ", effect_OP.EffectOp.ToString(), effect_OP.LoopCount, effect_OP.EffectBlockIndex)); switch (effect_OP.EffectOp) { case FFBOP.EFF_START: lock (vibThreadSentry) { Trace.WriteLine("Effect Start"); srcDevice.EffectBlocks[(byte)effectBlockIndex].Start(effect_OP.LoopCount); } break; case FFBOP.EFF_STOP: lock (vibThreadSentry) { Trace.WriteLine("Effect Stop"); srcDevice.EffectBlocks[(byte)effectBlockIndex].Stop(); } break; default: Trace.WriteLine("Error: Unkown command"); break; } break; case FFBPType.PT_BLKFRREP: Trace.WriteLine("Free Block"); lock (vibThreadSentry) { srcDevice.RemoveBlock((byte)effectBlockIndex); } break; case FFBPType.PT_CTRLREP: FFB_CTRL control = (FFB_CTRL)0; if (joystick.Ffb_h_DevCtrl(data, ref control) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Dev Control"); return; } //byte[] rawP2 = new byte[0]; //int len2 = 0; //uint transfertype2 = 0; //joystick.Ffb_h_Packet(data, ref transfertype2, ref len2, ref rawP2); //Trace.WriteLine(String.Format("DevControlThing : {0}", BitConverter.ToUInt16(rawP2, len2 - 2))); switch (control) { case FFB_CTRL.CTRL_ENACT: Trace.WriteLine("Enable all actuators (Not Supported)"); break; case FFB_CTRL.CTRL_DISACT: Trace.WriteLine("Disable all actuators (Not Supported)"); break; case FFB_CTRL.CTRL_STOPALL: Trace.WriteLine("Stop All Effects"); //Set All To Zero + Pause foreach (BaseEffectBlock peffect in srcDevice.EffectBlocks.Values) { peffect.Stop(); } break; case FFB_CTRL.CTRL_DEVRST: Trace.WriteLine("Reset Device"); lock (vibThreadSentry) { srcDevice.ClearBlocks(); srcDevice.DevicePaused = false; } break; case FFB_CTRL.CTRL_DEVPAUSE: Trace.WriteLine("Pause all effects"); foreach (BaseEffectBlock peffect in srcDevice.EffectBlocks.Values) { peffect.DevPause(); } srcDevice.DevicePaused = true; break; case FFB_CTRL.CTRL_DEVCONT: Trace.WriteLine("Resume all effects paused by DevPause"); foreach (BaseEffectBlock peffect in srcDevice.EffectBlocks.Values) { peffect.DevPause(); } srcDevice.DevicePaused = false; break; default: Trace.WriteLine("Unkown Command"); break; } break; case FFBPType.PT_GAINREP: byte gain = 1; if (joystick.Ffb_h_DevGain(data, ref gain) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read Dev Gain Command"); return; } Trace.WriteLine((string.Format("Gain Set : {0}", gain))); srcDevice.DeviceGain = (float)gain / vJoyConstants.EFFECT_MAX_GAIN; break; case FFBPType.PT_SETCREP: Trace.WriteLine("Error: Unkown command"); break; //Feature case FFBPType.PT_NEWEFREP: FFBEType nextEffect = (FFBEType)0; if (joystick.Ffb_h_EffNew(data, ref nextEffect) != ERROR_SUCCESS) { Trace.WriteLine("Error: Unable read new effect"); return; } Trace.WriteLine((string.Format("Incomming Effect : {0}", nextEffect.ToString()))); //Add + Load Block //Use effecct type as an index byte free_ebi = srcDevice.NextKey(); if (free_ebi != 0) { BaseEffectBlock newBlock; switch (nextEffect) { //ET_NONE case FFBEType.ET_CONST: newBlock = new ConstEffectBlock(); break; case FFBEType.ET_RAMP: newBlock = new RampEffectBlock(); break; case FFBEType.ET_SQR: newBlock = new SquareEffectBlock(); break; case FFBEType.ET_SINE: newBlock = new SineEffectBlock(); break; case FFBEType.ET_TRNGL: newBlock = new TrangleEffectBlock(); break; case FFBEType.ET_STUP: newBlock = new SawUpEffectBlock(); break; case FFBEType.ET_STDN: newBlock = new SawDownEffectBlock(); break; //Conditinal effects (unsurported) case FFBEType.ET_SPRNG: case FFBEType.ET_DMPR: case FFBEType.ET_INRT: case FFBEType.ET_FRCTN: Trace.WriteLine("Unsupported Conditinal Effect"); newBlock = new NullEffectBlock(); break; case FFBEType.ET_CSTM: //Custom (need test case) Trace.WriteLine("Unsupported Custom Effect"); newBlock = new NullEffectBlock(); break; default: Trace.WriteLine("Unkown Effect"); newBlock = new NullEffectBlock(); break; } if (newBlock != null) { newBlock.m_effectType = nextEffect; //TODO, If Blockload support arrives //Do AddBlock/ebi selection @ Blockload lock (vibThreadSentry) { srcDevice.AddBlock(free_ebi, newBlock); } } } break; case FFBPType.PT_BLKLDREP: Trace.WriteLine("BULK LOAD (Not Supported)"); break; case FFBPType.PT_POOLREP: Trace.WriteLine("Pool Report (Not supported)"); break; default: Trace.WriteLine("Error: Unkown command"); break; } }
/// <summary> /// Called when vJoy has a new FFB packet. /// WARNING This is called from a thread pool managed by windows. /// The thread itself is created and managed by vJoyInterface.dll. /// Do not overload it, else you will me missing FFB packets from /// third party application. /// </summary> /// <param name="ffbDataPtr"></param> /// <param name="userData"></param> public void FfbFunction1(IntPtr data, object userdata) { // Packet Header //copy ffb packet to managed structure InternalFfbPacket packet = (InternalFfbPacket)Marshal.PtrToStructure(data, typeof(InternalFfbPacket)); /////// Packet Device ID, and Type Block Index (if exists) #region Packet Device ID, and Type Block Index int DeviceID = 0, BlockIndex = 0; FFBPType Type = new FFBPType(); #if CONSOLE_DUMP string TypeStr = ""; Console.WriteLine("============= FFB Packet size Size {0} =============", (int)(packet.DataSize)); #endif if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DeviceID(data, ref DeviceID)) { #if CONSOLE_DUMP Console.WriteLine(" > Device ID: {0}", DeviceID); #endif } if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Type(data, ref Type)) { #if CONSOLE_DUMP if (!PacketType2Str(Type, ref TypeStr)) { Console.WriteLine(" > Packet Type: {0}", Type); } else { Console.WriteLine(" > Packet Type: {0}", TypeStr); } #endif switch (Type) { case FFBPType.PT_POOLREP: Console.WriteLine("POOL REPORT !!!"); break; case FFBPType.PT_BLKLDREP: Console.WriteLine("BLOCK LOAD REPORT !!!"); break; case FFBPType.PT_BLKFRREP: Console.WriteLine("BLOCK FREE REPORT !!!"); break; } } // Effect block index only used when simultaneous effects should be done by // underlying hardware, which is not the case for a single motor driving wheel if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EBI(data, ref BlockIndex)) { #if CONSOLE_DUMP Console.WriteLine(" > Effect Block Index: {0}", BlockIndex); #endif // Remove 1 to get [0..n-1] range BlockIndex--; } #endregion #region Create new effect Type FFBEType EffectType = new FFBEType(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffNew(data, ref EffectType)) { #if CONSOLE_DUMP if (EffectType2Str(EffectType, ref TypeStr)) { Console.WriteLine(" >> Effect Type: {0}", TypeStr); } else { Console.WriteLine(" >> Effect Type: Unknown"); } #endif } #endregion #region Condition vJoy.FFB_EFF_COND Condition = new vJoy.FFB_EFF_COND(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Cond(data, ref Condition)) { #if CONSOLE_DUMP if (Condition.isY) { Console.WriteLine(" >> Y Axis"); } else { Console.WriteLine(" >> X Axis"); } Console.WriteLine(" >> Center Point Offset: {0}", TwosCompWord2Int(Condition.CenterPointOffset)); Console.WriteLine(" >> Positive Coefficient: {0}", TwosCompWord2Int(Condition.PosCoeff)); Console.WriteLine(" >> Negative Coefficient: {0}", TwosCompWord2Int(Condition.NegCoeff)); Console.WriteLine(" >> Positive Saturation: {0}", Condition.PosSatur); Console.WriteLine(" >> Negative Saturation: {0}", Condition.NegSatur); Console.WriteLine(" >> Dead Band: {0}", Condition.DeadBand); #endif // Skip all processing if Y axis (single axis for wheel FFB!) if (Condition.isY) { // Leave early! return; } FFBManager.SetLimitsParams(BlockIndex, TwosCompWord2Int(Condition.CenterPointOffset) * Scale_FFB_to_u, Condition.DeadBand * Scale_FFB_to_u, TwosCompWord2Int(Condition.PosCoeff) * Scale_FFB_to_u, TwosCompWord2Int(Condition.NegCoeff) * Scale_FFB_to_u, Condition.PosSatur * Scale_FFB_to_u, -Condition.NegSatur * Scale_FFB_to_u); } #endregion /////// Effect Report #region Effect Report vJoy.FFB_EFF_REPORT Effect = new vJoy.FFB_EFF_REPORT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Report(data, ref Effect)) { #if CONSOLE_DUMP if (!EffectType2Str(Effect.EffectType, ref TypeStr)) { Console.WriteLine(" >> Effect Report: {0} {1}", (int)Effect.EffectType, Effect.EffectType.ToString()); } else { Console.WriteLine(" >> Effect Report: {0}", TypeStr); } #endif if (Effect.Polar) { #if CONSOLE_DUMP Console.WriteLine(" >> Direction: {0} deg ({1})", Polar2Deg(Effect.Direction), Effect.Direction); #endif FFBManager.SetDirection(BlockIndex, Polar2Deg(Effect.Direction)); } else { #if CONSOLE_DUMP Console.WriteLine(" >> X Direction: {0}", Effect.DirX); Console.WriteLine(" >> Y Direction: {0}", Effect.DirY); #endif FFBManager.SetDirection(BlockIndex, Effect.DirX); } #if CONSOLE_DUMP if (Effect.Duration == 0xFFFF) { Console.WriteLine(" >> Duration: Infinit"); } else { Console.WriteLine(" >> Duration: {0} MilliSec", (int)(Effect.Duration)); } if (Effect.TrigerRpt == 0xFFFF) { Console.WriteLine(" >> Trigger Repeat: Infinit"); } else { Console.WriteLine(" >> Trigger Repeat: {0}", (int)(Effect.TrigerRpt)); } if (Effect.SamplePrd == 0xFFFF) { Console.WriteLine(" >> Sample Period: Infinit"); } else { Console.WriteLine(" >> Sample Period: {0}", (int)(Effect.SamplePrd)); } Console.WriteLine(" >> Gain: {0}%%", Byte2Percent(Effect.Gain)); #endif if (Effect.Duration == 65535) { FFBManager.SetDuration(BlockIndex, -1.0); } else { FFBManager.SetDuration(BlockIndex, Effect.Duration); } FFBManager.SetEffectGain(BlockIndex, Byte2Percent(Effect.Gain) * 0.01); switch (Effect.EffectType) { case FFBEType.ET_CONST: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.CONSTANT_TORQUE); break; case FFBEType.ET_RAMP: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.RAMP); break; case FFBEType.ET_INRT: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.INERTIA); break; case FFBEType.ET_SPRNG: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.SPRING); break; case FFBEType.ET_DMPR: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.DAMPER); break; case FFBEType.ET_FRCTN: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.FRICTION); break; // Periodic case FFBEType.ET_SQR: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.SQUARE); break; case FFBEType.ET_SINE: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.SINE); break; case FFBEType.ET_TRNGL: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.TRIANGLE); break; case FFBEType.ET_STUP: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.SAWTOOTHUP); break; case FFBEType.ET_STDN: FFBManager.SetEffect(BlockIndex, AFFBManager.EffectTypes.SAWTOOTHDOWN); break; } } #endregion #region PID Device Control FFB_CTRL Control = new FFB_CTRL(); string CtrlStr = ""; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevCtrl(data, ref Control) && DevCtrl2Str(Control, ref CtrlStr)) { #if CONSOLE_DUMP Console.WriteLine(" >> PID Device Control: {0}", CtrlStr); #endif switch (Control) { case FFB_CTRL.CTRL_DEVRST: // device reset FFBManager.DevReset(); break; case FFB_CTRL.CTRL_ENACT: FFBManager.DevEnable(); break; case FFB_CTRL.CTRL_DISACT: FFBManager.DevDisable(); break; } } #endregion #region Effect Operation vJoy.FFB_EFF_OP Operation = new vJoy.FFB_EFF_OP(); string EffOpStr = ""; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_EffOp(data, ref Operation) && EffectOpStr(Operation.EffectOp, ref EffOpStr)) { #if CONSOLE_DUMP Console.WriteLine(" >> Effect Operation: {0}", EffOpStr); if (Operation.LoopCount == 0xFF) { Console.WriteLine(" >> Loop until stopped"); } else { Console.WriteLine(" >> Loop {0} times", (int)(Operation.LoopCount)); } #endif switch (Operation.EffectOp) { case FFBOP.EFF_START: // Start the effect identified by the Effect Handle. FFBManager.StartEffect(BlockIndex, (int)(Operation.LoopCount)); break; case FFBOP.EFF_STOP: // Stop the effect identified by the Effect Handle. FFBManager.StopEffect(BlockIndex); break; case FFBOP.EFF_SOLO: // Start the effect identified by the Effect Handle and stop all other effects. FFBManager.StartEffect(BlockIndex, 1); break; } } #endregion #region Global Device Gain byte Gain = 0; if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_DevGain(data, ref Gain)) { #if CONSOLE_DUMP Console.WriteLine(" >> Global Device Gain: {0}", Byte2Percent(Gain)); #endif FFBManager.SetDeviceGain(Byte2Percent(Gain) * 0.01); } #endregion #region Envelope vJoy.FFB_EFF_ENVLP Envelope = new vJoy.FFB_EFF_ENVLP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Envlp(data, ref Envelope)) { #if CONSOLE_DUMP Console.WriteLine(" >> Attack Level: {0}", Envelope.AttackLevel); Console.WriteLine(" >> Fade Level: {0}", Envelope.FadeLevel); Console.WriteLine(" >> Attack Time: {0}", (int)(Envelope.AttackTime)); Console.WriteLine(" >> Fade Time: {0}", (int)(Envelope.FadeTime)); #endif FFBManager.SetEnveloppeParams(BlockIndex, Envelope.AttackTime, Envelope.AttackLevel, Envelope.FadeTime, Envelope.FadeLevel); } #endregion #region Periodic vJoy.FFB_EFF_PERIOD EffPrd = new vJoy.FFB_EFF_PERIOD(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Period(data, ref EffPrd)) { #if CONSOLE_DUMP Console.WriteLine(" >> Magnitude: {0}", EffPrd.Magnitude); Console.WriteLine(" >> Offset: {0}", TwosCompWord2Int(EffPrd.Offset)); Console.WriteLine(" >> Phase: {0}", EffPrd.Phase * 3600 / 255); Console.WriteLine(" >> Period: {0}", (int)(EffPrd.Period)); #endif FFBManager.SetPeriodicParams(BlockIndex, (double)EffPrd.Magnitude * Scale_FFB_to_u, TwosCompWord2Int(EffPrd.Offset) * Scale_FFB_to_u, EffPrd.Phase * 0.01, EffPrd.Period); } #endregion #region Ramp Effect vJoy.FFB_EFF_RAMP RampEffect = new vJoy.FFB_EFF_RAMP(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Ramp(data, ref RampEffect)) { #if CONSOLE_DUMP Console.WriteLine(" >> Ramp Start: {0}", TwosCompWord2Int(RampEffect.Start)); Console.WriteLine(" >> Ramp End: {0}", TwosCompWord2Int(RampEffect.End)); #endif FFBManager.SetRampParams(BlockIndex, RampEffect.Start * Scale_FFB_to_u, RampEffect.End * Scale_FFB_to_u); } #endregion #region Constant Effect vJoy.FFB_EFF_CONSTANT CstEffect = new vJoy.FFB_EFF_CONSTANT(); if ((uint)ERROR.ERROR_SUCCESS == Joystick.Ffb_h_Eff_Constant(data, ref CstEffect)) { #if CONSOLE_DUMP Console.WriteLine(" >> Block Index: {0}", TwosCompWord2Int(CstEffect.EffectBlockIndex)); Console.WriteLine(" >> Magnitude: {0}", TwosCompWord2Int(CstEffect.Magnitude)); #endif FFBManager.SetConstantTorqueEffect(BlockIndex, (double)CstEffect.Magnitude * Scale_FFB_to_u); } #endregion #if DUMP_PACKET FfbFunction(data); #endif #if CONSOLE_DUMP Console.WriteLine("===================================================="); #endif }