Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Prevent crash when waking PC up from sleep #1806

Merged
merged 4 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions MobiFlight/Joysticks/JoystickManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ private JoystickDefinition GetDefinitionByInstanceName(String instanceName)
return Definitions.Find(definition => definition.InstanceName == instanceName);
}

/// <summary>
/// Finds a JoystickDefinition by the device's vendor and product id.
/// </summary>
/// <param name="vendorId">The vendor id of the device.</param>
/// <param name="productId">The product id of the device.</param>
/// <returns>The first definition matching the product id, or null if none found.</returns>
private JoystickDefinition GetDefinitionByProductId(int vendorId, int productId)
{
return Definitions.Find(def => (def.ProductId == productId && def.VendorId == vendorId));
}

/// <summary>
/// Loads all joystick definitions from disk.
/// </summary>
Expand Down Expand Up @@ -158,16 +169,19 @@ public async void Connect()

Joystick js;
var diJoystick = new SharpDX.DirectInput.Joystick(di, d.InstanceGuid);
var productId = diJoystick.Properties.ProductId;
var vendorId = diJoystick.Properties.VendorId;
if (d.InstanceName == "Octavi" || d.InstanceName == "IFR1")
{
// statically set this to Octavi until we might support (Octavi|IFR1) or similar
js = new Octavi(diJoystick, GetDefinitionByInstanceName("Octavi"));
}
else if (diJoystick.Properties.VendorId == 0x4098 && diJoystick.Properties.ProductId == 0xBB10)
else if (vendorId == 0x4098 && productId == 0xBB10)
{
js = new WinwingFcu(diJoystick, GetDefinitionByInstanceName("WINWING FCU"));
var joystickDef = GetDefinitionByProductId(vendorId, productId);
js = new WinwingFcu(diJoystick, joystickDef, productId);
}
else if (diJoystick.Properties.VendorId == 0x231D)
else if (vendorId == 0x231D)
{
// VKB devices are highly configurable. DirectInput names can have old values cached in the registry, but HID names seem to be immune to that.
// Also trim the extraneous whitespaces on VKB device names.
Expand Down
53 changes: 32 additions & 21 deletions MobiFlight/Joysticks/WinwingFcu/WinwingFcu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ internal class HidBuffer

internal class WinwingFcu : Joystick
{
readonly uint VendorId = 0x4098;
readonly uint ProductId = 0xBB10;
private readonly int VendorId = 0x4098;
private int ProductId = 0xBB10;
IHidDevice Device { get; set; }

private const int SPD_DEC = 10;
Expand All @@ -40,15 +40,17 @@ internal class WinwingFcu : Joystick
private WinwingFcuReport CurrentReport = new WinwingFcuReport();
private WinwingFcuReport PreviousReport = new WinwingFcuReport();
private HidBuffer HidDataBuffer = new HidBuffer();
private WinwingDisplayControl DisplayControl = new WinwingDisplayControl();
private WinwingDisplayControl DisplayControl;

private List<IBaseDevice> LcdDevices = new List<IBaseDevice>();
private List<ListItem<IBaseDevice>> LedDevices = new List<ListItem<IBaseDevice>>();
public WinwingFcu(SharpDX.DirectInput.Joystick joystick, JoystickDefinition definition) : base(joystick, definition)


public WinwingFcu(SharpDX.DirectInput.Joystick joystick, JoystickDefinition def, int productId) : base(joystick, def)
{
Definition = definition;
Definition = def;
ProductId = productId;
DisplayControl = new WinwingDisplayControl(productId);
var displayNames = DisplayControl.GetDisplayNames();
var ledNames = DisplayControl.GetLedNames();

Expand Down Expand Up @@ -79,7 +81,7 @@ public async override void Connect(IntPtr handle)
base.Connect(handle);
DisplayControl.Connect();

var hidFactory = new FilterDeviceDefinition(vendorId: VendorId, productId: ProductId).CreateWindowsHidDeviceFactory();
var hidFactory = new FilterDeviceDefinition(vendorId: (uint)VendorId, productId: (uint)ProductId).CreateWindowsHidDeviceFactory();
var deviceDefinitions = (await hidFactory.GetConnectedDeviceDefinitionsAsync().ConfigureAwait(false)).ToList();
Device = (IHidDevice)await hidFactory.GetDeviceAsync(deviceDefinitions.First()).ConfigureAwait(false);
await Device.InitializeAsync().ConfigureAwait(false);
Expand Down Expand Up @@ -126,21 +128,20 @@ protected override void EnumerateDevices()
}
}

private bool IsBitSet(uint intToCheck, int buttonId)
{
int pos = buttonId - 1;
return (intToCheck & (1 << pos)) != 0;
}

private void CheckForButtonTrigger(uint changes, MobiFlightButton.InputEvent inputEvent)
private void CheckForButtonTrigger(uint changes, MobiFlightButton.InputEvent inputEvent, int offset)
{
if (changes > 0)
{
foreach (var button in ButtonsToTrigger)
for (int i = 0; i < 32; i++)
{
if (IsBitSet(intToCheck: changes, buttonId: button.Key))
if ((changes & (1 << i)) != 0) // IsBitSet
{
TriggerButtonPress(button.Value, inputEvent);
// Button IDs start with 1
bool hasValue = ButtonsToTrigger.TryGetValue((i + offset + 1), out var button);
if (hasValue)
{
TriggerButtonPress(button, inputEvent);
}
}
}
}
Expand Down Expand Up @@ -188,14 +189,24 @@ private void InputReportReceived(HidBuffer hidBuffer)
{
CurrentReport.CopyTo(PreviousReport);
PreviousReport.ButtonState = ~PreviousReport.ButtonState; // to retrigger
PreviousReport.ButtonState2 = ~PreviousReport.ButtonState2; // to retrigger
PreviousReport.ButtonState3 = ~PreviousReport.ButtonState3; // to retrigger
DoInitialize = false;
}

// Detect and Trigger Button Events
uint pressed = CurrentReport.ButtonState & ~PreviousReport.ButtonState; // rising edges
uint released = PreviousReport.ButtonState & ~CurrentReport.ButtonState; // falling edges
CheckForButtonTrigger(pressed, MobiFlightButton.InputEvent.PRESS);
CheckForButtonTrigger(released, MobiFlightButton.InputEvent.RELEASE);
uint pressed2 = CurrentReport.ButtonState2 & ~PreviousReport.ButtonState2; // rising edges
uint released2 = PreviousReport.ButtonState2 & ~CurrentReport.ButtonState2; // falling edges
uint pressed3 = CurrentReport.ButtonState3 & ~PreviousReport.ButtonState3; // rising edges
uint released3 = PreviousReport.ButtonState3 & ~CurrentReport.ButtonState3; // falling edges
CheckForButtonTrigger(pressed, MobiFlightButton.InputEvent.PRESS, 0);
CheckForButtonTrigger(released, MobiFlightButton.InputEvent.RELEASE, 0);
CheckForButtonTrigger(pressed2, MobiFlightButton.InputEvent.PRESS, 32);
CheckForButtonTrigger(released2, MobiFlightButton.InputEvent.RELEASE, 32);
CheckForButtonTrigger(pressed3, MobiFlightButton.InputEvent.PRESS, 64);
CheckForButtonTrigger(released3, MobiFlightButton.InputEvent.RELEASE, 64);

// Detect and Trigger Encoder Turns
int spdIncrement = CurrentReport.SpdEncoderValue - PreviousReport.SpdEncoderValue;
Expand Down
12 changes: 11 additions & 1 deletion MobiFlight/Joysticks/WinwingFcu/WinwingFcuReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ internal class WinwingFcuReport
{
public uint ReportId { get; set; }
public uint ButtonState { get; set; }
public uint ButtonState2 { get; set; }
public uint ButtonState3 { get; set; }
public ushort SpdEncoderValue { get; set; }
public ushort HdgEncoderValue { get; set; }
public ushort AltEncoderValue { get; set; }
Expand All @@ -19,6 +21,8 @@ public void CopyTo(WinwingFcuReport targetReport)
{
targetReport.ReportId = this.ReportId;
targetReport.ButtonState = this.ButtonState;
targetReport.ButtonState2 = this.ButtonState2;
targetReport.ButtonState3 = this.ButtonState3;
targetReport.SpdEncoderValue = this.SpdEncoderValue;
targetReport.AltEncoderValue = this.AltEncoderValue;
targetReport.HdgEncoderValue = this.HdgEncoderValue;
Expand All @@ -33,6 +37,8 @@ public void ParseReport(HidBuffer hidBuffer)
{
// get 32 bit Button report field - First 4 bytes: uint: [3][2][1][0]
ButtonState = ((uint)data[0] + ((uint)data[1] << 8) + ((uint)data[2] << 16) + ((uint)data[3] << 24));
ButtonState2 = ((uint)data[4] + ((uint)data[5] << 8) + ((uint)data[6] << 16) + ((uint)data[7] << 24));
ButtonState3 = ((uint)data[8] + ((uint)data[9] << 8) + ((uint)data[10] << 16) + ((uint)data[11] << 24));

if (IsFirmwareGreaterOrEqual_1_16) // Since firmware v1.16
{
Expand All @@ -54,13 +60,17 @@ public void ParseReport(HidBuffer hidBuffer)
// Is firmware report
if (data[5] == 0x02 && data[4] == 0x05 && data[0] == 0x10)
{
Log.Instance.log($"WINWING FCU Firmware: v{data[9].ToString("X2")}.{data[8].ToString("X2")}", LogSeverity.Debug);
LogFirmware(data, "WINWING FCU");
if (data[9] == 1 && data[8] < 0x16)
{
IsFirmwareGreaterOrEqual_1_16 = false;
}
}
}
}
private void LogFirmware(byte[] data, string device)
{
Log.Instance.log($"{device} Firmware: v{data[9].ToString("X2")}.{data[8].ToString("X2")}", LogSeverity.Debug);
}
}
}
Binary file modified lib/MobiFlightWwFcu.dll
Binary file not shown.
Loading