private static async Task <TimingResult> TestTaskInner(CancellationToken token) { Stopwatch s = Stopwatch.StartNew(); TimeSpan prevValue = TimeSpan.Zero; int i = 0; while (true) { Console.WriteLine(s.Elapsed.TotalMilliseconds); await MultimediaTimer.Delay(1, token); if (Console.KeyAvailable) { break; } i++; } return(new TimingResult() { Elapsed = s.Elapsed, Iterations = i }); }
public Core_Interception() { _providerDescriptor = new ProviderDescriptor { ProviderName = ProviderName }; ProcessSettingsFile(); _deviceLibrary = new IceptDeviceLibrary(_providerDescriptor, _blockingEnabled); if (_deviceLibrary.GetInputList().Devices?.Count > 0) { _isLive = true; _errorMessage = string.Empty; } else { _isLive = false; _errorMessage = "No Interception devices found, driver assumed to not be installed"; } _deviceContext = ManagedWrapper.CreateContext(); StartPollingIfNeeded(); //_pollThreadDesired = true; _timer = new MultimediaTimer() { Interval = _pollRate }; _timer.Elapsed += DoPoll; }
protected TimerState(PlayerStateController playerStateController, VideoSource videoSource, IFrameDisplay frameDisplay) : base(playerStateController, videoSource, frameDisplay) { _timer = new MultimediaTimer { Mode = TimerMode.Periodic }; _timeProc = new MultimediaTimer.TimeProc(Tick); }
public Manager() { _deviceContext = ManagedWrapper.CreateContext(); _timer = new MultimediaTimer() { Interval = _pollRate }; _timer.Elapsed += DoPoll; }
/// <summary> /// Default base constructor /// </summary> public AFFBManager(int refreshPeriod_ms) { RefreshPeriod_ms = refreshPeriod_ms; Tick_per_s = 1000.0 / (double)RefreshPeriod_ms; Timer = new MultimediaTimer(refreshPeriod_ms); for (int i = 0; i < RunningEffects.Length; i++) { RunningEffects[i] = new Effect(); RunningEffects[i].Reset(); } NewEffect.Reset(); }
private static void TestMultimediaTimer() { Stopwatch s = new Stopwatch(); using (var timer = new MultimediaTimer() { Interval = 1 }) { timer.Elapsed += (o, e) => Console.WriteLine(s.ElapsedMilliseconds); s.Start(); timer.Start(); Console.ReadKey(); timer.Stop(); } }
public void Subscribe(int vid, int pid, dynamic callback) { _callback = callback; _filteredDevice = HelperFunctions.GetDeviceId(_deviceContext, false, vid, pid, 1); if (_filteredDevice == 0) { throw new Exception($"Could not find device with VID {vid}, PID {pid}"); } ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice, ManagedWrapper.Filter.All); _timer = new MultimediaTimer() { Interval = 10 }; _timer.Elapsed += DoPoll; _timer.Start(); }
public PatternPlayer(IEnumerable <Instrument> instruments, int bpm, MultimediaTimer timer, bool loop) { _masteringVoice = new MasteringVoice(_xAudio2); _bpm = bpm; _loop = loop; foreach (Instrument instrument in instruments) { _instrumentStates.Add(instrument, new InstrumentState(new Sound(instrument, _xAudio2), instrument.Beats.Count)); } double interval = (60d / _bpm) * 1000d; _timer = timer ?? throw new ArgumentNullException(nameof(timer)); _timer.Interval = (int)interval; _timer.Elapsed += OnElapsed; }
/// <summary> /// Sets up calibration procedure and the tracking client /// and wires the events. Then reads settings from file. /// </summary> protected override sealed void Initialize() { this.counter = 0; this.trackingTimer = new Timer(); this.stopWatch = new Stopwatch(); this.multimediaTimer = new MultimediaTimer(); this.multimediaTimer.Tick += this.TrackingTimerTick; if (File.Exists(this.SettingsFile)) { this.mouseOnlySettings = this.DeserializeSettings(this.SettingsFile); } else { this.mouseOnlySettings = new MouseOnlySetting(); this.SerializeSettings(this.mouseOnlySettings, this.SettingsFile); } this.UpdateSettings(); }
public Core_Interception() { _providerDescriptor = new ProviderDescriptor { ProviderName = ProviderName }; _deviceLibrary = new IceptDeviceLibrary(_providerDescriptor); ProcessSettingsFile(); _deviceContext = ManagedWrapper.CreateContext(); StartPollingIfNeeded(); //_pollThreadDesired = true; _timer = new MultimediaTimer() { Interval = _pollRate }; _timer.Elapsed += DoPoll; }
private DataReader() { _scudTimer = new MultimediaTimer(1000); _scudTimer.Elapsed += _scudTimerElapsed; _iptTimer = new MultimediaTimer(250); _iptTimer.Elapsed += _iptTimer_Elapsed; MbCliWrapper.Connected += (s, e) => { _isScudConnected = true; }; MbCliWrapper.Disconnected += (s, e) => { _isScudConnected = false; }; MbCliWrapper.Error += (s, e) => { OnScudError( new DataReaderErrorEventArgs(e.ErrorCode, string.Format("Ошибка СКУД.\n{0}", e.ErrorText))); }; }
private static TimingResult TestMultimediaTimer() { TimeSpan total = TimeSpan.Zero; int iterations = 0; Stopwatch s = new Stopwatch(); using (var timer = new MultimediaTimer() { Interval = 1 }) { timer.Elapsed += (o, e) => { var ts = s.Elapsed; lock (s) { total += ts; iterations++; } Console.WriteLine(ts.TotalMilliseconds); }; s.Start(); timer.Start(); Console.ReadKey(true); timer.Stop(); } lock (s) { return(new TimingResult() { Elapsed = s.Elapsed, Iterations = iterations }); } }
/// <summary> /// Starts the /// </summary> public void StartPdoExchangeTask() { /* Declare multimedia Timer with 20 ms interval */ MmTimer = new MultimediaTimer { Interval = 20 }; /* Timer event in charge of the exchange of PDO data and for the calling of Scope SDOs */ MmTimer.Elapsed += /*async*/ (o, e) => { /* Call an exchange of PDO */ wkc_pdo = EcSendRecieveProcessdataExtern(); for (int i = 0; i < Devices.Count; i++) { if (Devices[i] is PCS device) { device.pdo_output_map.controlword = device.Controlword; device.pdo_output_map.target_position = device.TargetPosition; device.pdo_output_map.target_velocity = device.TargetVelocity; device.pdo_output_map.modes_of_oper = device.TargetMode; /* From low-level soem code copy the pdo data */ EcCopyPdos(device.SlaveNumber, ref device.pdo_input_map, device.pdo_output_map); device.stateMachineDsp402.StateWord = device.pdo_input_map.statusword; //device.CurrentMode = device.pdo_input_map.modes_of_oper_disp; //device.ActualPos = device.pdo_input_map.actual_position; //device.ActualVel = device.pdo_input_map.actual_velocity; } } //wkc_wathchdog = (wkc_pdo < 0) ? wkc_wathchdog + 1 : 0; /* check for worker counter, increase watchdog if worker counter is <=0 */ Console.WriteLine(wkc_pdo); if (wkc_pdo < 3) { wkc_wathchdog += 1; } else { wkc_wathchdog = 0; } if (wkc_wathchdog > 1000) { Disconnect(); //MW.Dispatcher.Invoke(() => //{ //await MW.ShowMessageAsync("Client Disconnected", "Lost contact to device.");+ //MessageBox.Show("Client Disconnected. Lost contact to device."); //}); } }; /* start multimedia timer */ MmTimer.Start(); StartScopeTask(); timerUpdatePdoProperties.Elapsed += new ElapsedEventHandler(DoTimeEventUpdateProperties); //Non realtime relevant stuff timerUpdatePdoProperties.Interval = 50; // in ms timerUpdatePdoProperties.Enabled = true; timerUpdatePdoProperties.AutoReset = true; }
public TimerRegister(int StartAddress, int Length) : base(StartAddress, Length) { hiresTimer = new MultimediaTimer(1000); hiresTimer.Elapsed += new MultimediaElapsedEventHandler(Timer_Tick); }
public CommunicationUDP(UdpCommControl udpctl, CheckBox checkboxEoeRw) { MW = udpctl.MW; Devices.Clear(); Devices.Add(new PCS(this, 1, "Intec PCS", MW.ObjectDictionary)); (Devices[0] as PCS).EcStateMachine = EC_SM.EC_SM_NA; IpAddress = udpctl.Ipaddress; //create a new client client = UdpUser.ConnectTo(IpAddress, _port); commType = CommType.COMM_UDP; Connected = true; WriteFlag = checkboxEoeRw.IsChecked.Value; MmTimer = new MultimediaTimer { Interval = 100 }; Task <byte[]> ret; byte[] send_client_msg = new byte[182]; ts_cycle = new CancellationTokenSource(); CancellationToken ct = ts_cycle.Token; Task.Factory.StartNew(async() => { while (true) { if (ct.IsCancellationRequested) /* TRUE when ts_cyle.Cancel() is called */ { break; /* Get out of loop to end thread*/ } send_client_msg = new byte[182]; if (Connected && Devices[0] is PCS device) { InsertPdoWriteControlword(); /* PDO 1 */ InsertPdoReadStatusword(); /* PDO 2 */ InsertPdoWriteTargetPosition(); /* PDO 3 */ InsertPdoReadActualPosition(); /* PDO 4 */ InsertPdoWriteTargetVelocity(); /* PDO 5 */ InsertPdoReadActualVelocity(); /* PDO 6 */ InsertPdoWriteTargetMode(); /* PDO 7 */ InsertPdoReadModeDisp(); /* PDO 8 */ InsertScopeObjects(); PutBufferInSendArray(ref send_client_msg); ret = SendUdp(send_client_msg); // This must be only thread to call SendUDP GetObjectsFromBuffer(ret.Result); } await Task.Delay(1); } }, ct); }
protected TimerState(PlayerStateController playerStateController, VideoSource videoSource, IFrameDisplay frameDisplay) : base(playerStateController, videoSource, frameDisplay) { _timer = new MultimediaTimer {Mode = TimerMode.Periodic}; _timeProc = new MultimediaTimer.TimeProc(Tick); }
private static void Delay(int ms) { MultimediaTimer.Delay(ms).Wait(); }
// // Tablet View Constructor // public WindowTabletView(Configuration config, TabletDriver driver) { if (config.TabletView.Borderless) { WindowStyle = WindowStyle.None; } InitializeComponent(); this.config = config; this.driver = driver; // Tablet renderer tabletRenderer = new TabletRenderer(config); canvasTabletView.Children.Add(tabletRenderer); // Offset texts Canvas.SetLeft(textTabletInfo, Canvas.GetLeft(textTabletInfo) + config.TabletView.OffsetText.X); Canvas.SetTop(textTabletInfo, Canvas.GetTop(textTabletInfo) + config.TabletView.OffsetText.Y); Canvas.SetLeft(textInput, Canvas.GetLeft(textInput) + config.TabletView.OffsetText.X); Canvas.SetTop(textInput, Canvas.GetTop(textInput) + config.TabletView.OffsetText.Y); Canvas.SetLeft(textOutput, Canvas.GetLeft(textOutput) + config.TabletView.OffsetText.X); Canvas.SetTop(textOutput, Canvas.GetTop(textOutput) + config.TabletView.OffsetText.Y); Canvas.SetLeft(textLatency, Canvas.GetLeft(textLatency) + config.TabletView.OffsetText.X); Canvas.SetTop(textLatency, Canvas.GetTop(textLatency) + config.TabletView.OffsetText.Y); // Background color Brush brush; try { brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(config.TabletView.BackgroundColor)); } catch (Exception) { brush = Brushes.White; } canvasTabletView.Background = brush; Background = brush; // Text colors try { brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(config.TabletView.InfoColor)); } catch (Exception) { brush = Brushes.Black; } textTabletInfo.Foreground = brush; try { brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(config.TabletView.LatencyColor)); } catch (Exception) { brush = Brushes.Black; } textLatency.Foreground = brush; textInput.Foreground = tabletRenderer.brushInput; textOutput.Foreground = tabletRenderer.brushOutput; // Text font try { FontFamilyConverter fontConverter = new FontFamilyConverter(); FontFamily fontFamily = (FontFamily)fontConverter.ConvertFromString(config.TabletView.Font); textTabletInfo.FontFamily = fontFamily; textInput.FontFamily = fontFamily; textOutput.FontFamily = fontFamily; textLatency.FontFamily = fontFamily; } catch (Exception) { } // Font size textTabletInfo.FontSize = config.TabletView.FontSize; textInput.FontSize = config.TabletView.FontSize; textOutput.FontSize = config.TabletView.FontSize; textLatency.FontSize = config.TabletView.FontSize; // Info text textTabletInfo.Text = config.TabletName + " - " + Utils.GetNumberString(config.TabletAreas[0].Width) + " x " + Utils.GetNumberString(config.TabletAreas[0].Height) + " mm → " + Utils.GetNumberString(config.ScreenAreas[0].Width, "0") + " x " + Utils.GetNumberString(config.ScreenAreas[0].Height, "0") + " px"; // // Update/draw timer // timer = new MultimediaTimer { Interval = 2 }; timer.Tick += UpdateTimer_Tick; // Last values lastPosition = new Vector(0, 0); lastUpdate = DateTime.Now; lastPressure = 0; // Average values velocity = 0; latency = 0; // Input loss hadInputLoss = true; lastInputStartTime = DateTime.Now; // Window events Loaded += WindowTabletView_Loaded; Closing += WindowTabletView_Closing; KeyDown += WindowTabletView_KeyDown; MouseDown += WindowTabletView_MouseDown; MouseUp += WindowTabletView_MouseUp; // Set GC mode to low latency GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; }
protected void ManagerThreadMethod() { __restart: Log("Program configured for " + Config.TranslatingModes, LogLevels.IMPORTANT); var boards = USBSerialIO.ScanAllCOMPortsForIOBoards(); if (boards.Length > 0) { IOboard = boards[0]; Log("Found io board on " + IOboard.COMPortName + " version=" + IOboard.BoardVersion + " type=" + IOboard.BoardDescription, LogLevels.IMPORTANT); } else { IOboard = null; if (Config.RunWithoutIOBoard) { Log("No boards found! Continue without real hardware", LogLevels.ERROR); } else { Log("No boards found! Thread will terminate", LogLevels.ERROR); Running = false; //Console.ReadKey(true); return; } } // Output system : lamps Outputs = new MAMEOutputWinAgent(); Outputs.Start(); switch (Config.TranslatingModes) { case FFBTranslatingModes.PWM_CENTERED: case FFBTranslatingModes.PWM_DIR: { FFB = new FFBManagerTorque(GlobalRefreshPeriod_ms); } break; case FFBTranslatingModes.MODEL3_UNKNOWN_DRVBD: { // Default to Scud/Daytona2 FFB = new FFBManagerModel3Scud(GlobalRefreshPeriod_ms); } break; case FFBTranslatingModes.MODEL3_LEMANS_DRVBD: { FFB = new FFBManagerModel3Lemans(GlobalRefreshPeriod_ms); } break; case FFBTranslatingModes.MODEL3_SCUD_DRVBD: { FFB = new FFBManagerModel3Scud(GlobalRefreshPeriod_ms); } break; default: throw new NotImplementedException("Unsupported FFB mode " + Config.TranslatingModes.ToString()); } // Use this to allow 1ms sleep granularity (else default is 16ms!!!) // This consumes more CPU cycles in the OS, but does improve // a lot reactivity when soft real-time work needs to be done. MultimediaTimer.SetTickGranularityOnWindows(); vJoy.EnablevJoy(); // Create joystick interface vJoy.Acquire(1); // Use first enumerated vJoy device vJoy.StartAndRegisterFFB(FFB); // Start FFB callback mechanism in vJoy // In case we want to use XInput/DInput devices to gather multiple inputs? //XInput(); //DirectInput(); if (IOboard != null) { Log("Initializing IO board", LogLevels.IMPORTANT); // Initialize board IOboard.PerformInit(); // Enable safety watchdog IOboard.EnableWD(); // Enable auto-streaming IOboard.StartStreaming(); } if (Config.VerbosevJoyManager) { Log("Start feeding..."); } // Start FFB manager FFB.Start(); // Internal values for special operation double prev_angle = 0.0; UInt32 autofire_mode_on = 0; uint error_counter = 0; UInt64 nextRun_ms = (UInt64)(MultimediaTimer.RefTimer.ElapsedMilliseconds); while (Running) { TickCount++; nextRun_ms += GlobalRefreshPeriod_ms; UInt64 now = (UInt64)(MultimediaTimer.RefTimer.ElapsedMilliseconds); int delay_ms = (int)(nextRun_ms - now); if (delay_ms >= 0) { // Sleep until next tick Thread.Sleep(delay_ms); } else { if (Config.VerbosevJoyManager) { Log("One period missed by " + (-delay_ms) + "ms", LogLevels.DEBUG); } } if (IOboard != null) { try { if (IOboard.IsOpen) { // Empty serial buffer if (delay_ms < 0) { IOboard.UpdateOnStreaming((-delay_ms) / GlobalRefreshPeriod_ms); } // Shift tick to synch with IOboard var before = MultimediaTimer.RefTimer.ElapsedMilliseconds; // Update status on received packets var nbproc = IOboard.UpdateOnStreaming(); var after = MultimediaTimer.RefTimer.ElapsedMilliseconds; // Delay is expected to be 1-2ms for processing in stream delay_ms = (int)(after - before); // Accept up to 2ms of delay (jitter), else consider we have if (delay_ms > 2 && nbproc == 1) { var add_delay = Math.Min(GlobalRefreshPeriod_ms - 1, delay_ms - 1); add_delay = 1; nextRun_ms += (ulong)add_delay; if (Config.VerbosevJoyManager) { Log("Read took " + delay_ms + "ms delay, adding " + add_delay + "ms to sync with IO board serial port", LogLevels.DEBUG); } } if (Config.VerbosevJoyManager) { if (nbproc > 1) { Log("Processed " + nbproc + " msg instead of 1", LogLevels.DEBUG); } } // Refresh wheel angle (between -1...1) if (IOboard.AnalogInputs.Length > 0) { // Scale analog input between 0..0xFFF, then map it to -1/+1, 0 being center var angle_u = ((double)IOboard.AnalogInputs[0]) * (2.0 / (double)0xFFF) - 1.0; // Refresh values in FFB manager if (IOboard.WheelStates.Length > 0) { // If full state given by IO board (should be in unit_per_s!) FFB.RefreshCurrentState(angle_u, IOboard.WheelStates[0], IOboard.WheelStates[1]); } else { // If only periodic position FFB.RefreshCurrentPosition(angle_u); } prev_angle = angle_u; } // For debugging purpose, add a 4th axis to display torque output uint[] axesXYRZplusSL0ForTrq = new uint[5]; IOboard.AnalogInputs.CopyTo(axesXYRZplusSL0ForTrq, 0); axesXYRZplusSL0ForTrq[4] = (uint)(FFB.OutputTorqueLevel * 0x7FF + 0x800); // Set values into vJoy report: // - axes vJoy.UpdateAxes12(axesXYRZplusSL0ForTrq); // - buttons (only32 supported for now) if (IOboard.DigitalInputs8.Length > 0) { UInt32 rawinput_states = 0; int rawidx = 0; // For each single input, process mapping, autofire and toggle for (int i = 0; i < Math.Min(4, IOboard.DigitalInputs8.Length); i++) { // Scan 8bit input block for (int j = 0; j < 8; j++) { // Default input value is current logic (false if not inverted) bool newrawval = Config.RawInputTovJoyMap[rawidx].IsInvertedLogic; // Check if input is "on" and invert default value if ((IOboard.DigitalInputs8[i] & (1 << j)) != 0) { // If was false, then set true newrawval = !newrawval; } // Now newrawval is the raw state of the input taking into account inv.logic // Bit corresponding to this input var rawbit = (UInt32)(1 << rawidx); // Store new state of raw input if (newrawval) { rawinput_states |= rawbit; } // Previous state of this input (for transition detection) var prev_state = (RawInputsStates & rawbit) != 0; // Check if we toggle the bit (or autofire mode) if (Config.RawInputTovJoyMap[rawidx].IsToggle) { // Toggle only if we detect a false->true transition in raw value if (newrawval && (!prev_state)) { // Toggle = xor on every vJoy buttons vJoy.ToggleButtons(Config.RawInputTovJoyMap[rawidx].vJoyBtns); } } else if (Config.RawInputTovJoyMap[rawidx].IsAutoFire) { // Autofire set, if false->true transition, then toggle autofire state if (newrawval && (!prev_state)) { // Enable/disable autofire autofire_mode_on ^= rawbit; } // No perform autofire toggle if autofire enabled if ((autofire_mode_on & rawbit) != 0) { // Toggle = xor every 20 periods if ((TickCount % 20) == 0) { vJoy.ToggleButtons(Config.RawInputTovJoyMap[rawidx].vJoyBtns); } } } else { // No toggle, no autofire : perform simple mask if (newrawval) { vJoy.SetButtons(Config.RawInputTovJoyMap[rawidx].vJoyBtns); } else { vJoy.ClearButtons(Config.RawInputTovJoyMap[rawidx].vJoyBtns); } } // Next input rawidx++; } } // Save raw input state for next run RawInputsStates = rawinput_states; } // - 360deg POV to view for wheel angle //vJoy.UpodateContinuousPOV((uint)((IOboard.AnalogInputs[0] / (double)0xFFF) * 35900.0) + 18000); // Update vJoy and send to driver every n ticks to limit workload on driver if ((TickCount % vJoyUpdate) == 0) { vJoy.PublishiReport(); } // Outputs (Lamps) if (Outputs != null) { // First 2 bits are unused for lamps (used by PWM Fwd/Rev) IOboard.DigitalOutputs8[0] = (byte)(Outputs.LampsValue); } // Now output torque to Pwm+Dir or drive board command switch (Config.TranslatingModes) { // PWM centered mode (50% = 0 torque) case FFBTranslatingModes.PWM_CENTERED: { // Latch a copy var outlevel = FFB.OutputTorqueLevel; // Enforce range again to be [-1; 1] outlevel = Math.Min(1.0, Math.Max(outlevel, -1.0)); UInt16 analogOut = (UInt16)(outlevel * 0x7FF + 0x800); IOboard.AnalogOutputs[0] = analogOut; } break; // PWM+dir mode (0% = 0 torque, direction given by first output) case FFBTranslatingModes.PWM_DIR: { // Latch a copy var outlevel = FFB.OutputTorqueLevel; if (outlevel >= 0.0) { UInt16 analogOut = (UInt16)(outlevel * 0xFFF); // Save into IOboard IOboard.AnalogOutputs[0] = analogOut; IOboard.DigitalOutputs8[0] |= 1 << 0; // set FwdCmd bit 0 IOboard.DigitalOutputs8[0] &= 0xFD; // clear RevCmd bit 1 } else { UInt16 analogOut = (UInt16)(-outlevel * 0xFFF); // Save into IOboard IOboard.AnalogOutputs[0] = analogOut; IOboard.DigitalOutputs8[0] |= 1 << 1; // set RevCmd bit 1 IOboard.DigitalOutputs8[0] &= 0xFE; // clear FwdCmd bit 0 } } break; // Driveboard translation mode case FFBTranslatingModes.MODEL3_UNKNOWN_DRVBD: case FFBTranslatingModes.MODEL3_LEMANS_DRVBD: case FFBTranslatingModes.MODEL3_SCUD_DRVBD: { // Latch a copy var outlevel = FFB.OutputEffectCommand; if (IOboard.DigitalOutputs8.Length > 1) { IOboard.DigitalOutputs8[1] = (byte)(outlevel & 0xFF); } } break; } // Save output state RawOutputsStates = 0; for (int i = 0; i < IOboard.DigitalOutputs8.Length; i++) { var shift = (i << 3); RawOutputsStates = (UInt32)(IOboard.DigitalOutputs8[i] << shift); } // Send all outputs - this will revive the watchdog! IOboard.SendOutputs(); } else { Log("Re-connecting to same IO board on port " + IOboard.COMPortName, LogLevels.IMPORTANT); IOboard.OpenComm(); // Enable safety watchdog IOboard.EnableWD(); // Enable auto-streaming IOboard.StartStreaming(); error_counter = 0; } } catch (Exception ex) { Log("IO board Failing with " + ex.Message, LogLevels.ERROR); try { if (IOboard.IsOpen) { IOboard.CloseComm(); } } catch (Exception ex2) { Log("Unable to close communication " + ex2.Message, LogLevels.ERROR); } error_counter++; if (error_counter > 10) { // Serious problem here, try complete restart with scanning FFB.Stop(); goto __restart; } System.Threading.Thread.Sleep(500); } } } ; MultimediaTimer.RestoreTickGranularityOnWindows(); if (Outputs != null) { Outputs.Stop(); } FFB.Stop(); if (IOboard != null) { IOboard.CloseComm(); } vJoy.Release(); }