From d0a8d17ed62b839183e10142f58d2a7547a959db Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Sat, 30 May 2020 15:13:21 -0700 Subject: [PATCH] Make System.Device.Gpio work on Mono --- .../Device/Gpio/Drivers/RaspberryPi3Driver.cs | 12 +++++++++++- .../System/Device/I2c/I2cDevice.cs | 14 +++++++++++++- .../System/Device/Pwm/PwmChannel.cs | 18 +++++++++++++++++- .../System/Device/Spi/SpiDevice.cs | 14 +++++++++++++- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/System.Device.Gpio/System/Device/Gpio/Drivers/RaspberryPi3Driver.cs b/src/System.Device.Gpio/System/Device/Gpio/Drivers/RaspberryPi3Driver.cs index 6d59312f9a..712baa8bcd 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/Drivers/RaspberryPi3Driver.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/Drivers/RaspberryPi3Driver.cs @@ -41,7 +41,7 @@ public RaspberryPi3Driver() } else { - _internalDriver = new Windows10Driver(); + _internalDriver = CreateWindows10GpioDriver(); _setSetRegister = (value) => throw new PlatformNotSupportedException(); _setClearRegister = (value) => throw new PlatformNotSupportedException(); _getSetRegister = () => throw new PlatformNotSupportedException(); @@ -49,6 +49,16 @@ public RaspberryPi3Driver() } } + [MethodImpl(MethodImplOptions.NoInlining)] + private static GpioDriver CreateWindows10GpioDriver() + { + // This wrapper is needed to prevent Mono from loading Windows10Driver + // which causes all fields to be loaded - one of such fields is WinRT type which does not + // exist on Linux which causes TypeLoadException. + // Using NoInlining and no explicit type prevents this from happening. + return new Windows10Driver(); + } + /// protected internal override int PinCount => 28; diff --git a/src/System.Device.Gpio/System/Device/I2c/I2cDevice.cs b/src/System.Device.Gpio/System/Device/I2c/I2cDevice.cs index a3155c0c08..bb045fa7b3 100644 --- a/src/System.Device.Gpio/System/Device/I2c/I2cDevice.cs +++ b/src/System.Device.Gpio/System/Device/I2c/I2cDevice.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Runtime.CompilerServices; + namespace System.Device.I2c { /// @@ -67,7 +69,7 @@ public static I2cDevice Create(I2cConnectionSettings settings) { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - return new Windows10I2cDevice(settings); + return CreateWindows10I2cDevice(settings); } else { @@ -75,6 +77,16 @@ public static I2cDevice Create(I2cConnectionSettings settings) } } + [MethodImpl(MethodImplOptions.NoInlining)] + private static I2cDevice CreateWindows10I2cDevice(I2cConnectionSettings settings) + { + // This wrapper is needed to prevent Mono from loading Windows10I2cDevice + // which causes all fields to be loaded - one of such fields is WinRT type which does not + // exist on Linux which causes TypeLoadException. + // Using NoInlining and no explicit type prevents this from happening. + return new Windows10I2cDevice(settings); + } + /// public void Dispose() { diff --git a/src/System.Device.Gpio/System/Device/Pwm/PwmChannel.cs b/src/System.Device.Gpio/System/Device/Pwm/PwmChannel.cs index 1bc98508e7..2f3014db0d 100644 --- a/src/System.Device.Gpio/System/Device/Pwm/PwmChannel.cs +++ b/src/System.Device.Gpio/System/Device/Pwm/PwmChannel.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Runtime.CompilerServices; + namespace System.Device.Pwm { /// @@ -61,7 +63,7 @@ public static PwmChannel Create( { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - return new Channels.Windows10PwmChannel( + return CreateWindows10PwmChannel( chip, channel, frequency, @@ -76,5 +78,19 @@ public static PwmChannel Create( dutyCyclePercentage); } } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static PwmChannel CreateWindows10PwmChannel(int chip, int channel, int frequency, double dutyCyclePercentage) + { + // This wrapper is needed to prevent Mono from loading Windows10PwmChannel + // which causes all fields to be loaded - one of such fields is WinRT type which does not + // exist on Linux which causes TypeLoadException. + // Using NoInlining and no explicit type prevents this from happening. + return new Channels.Windows10PwmChannel( + chip, + channel, + frequency, + dutyCyclePercentage); + } } } diff --git a/src/System.Device.Gpio/System/Device/Spi/SpiDevice.cs b/src/System.Device.Gpio/System/Device/Spi/SpiDevice.cs index 3edb5cc899..8f26242990 100644 --- a/src/System.Device.Gpio/System/Device/Spi/SpiDevice.cs +++ b/src/System.Device.Gpio/System/Device/Spi/SpiDevice.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Runtime.CompilerServices; + namespace System.Device.Spi { /// @@ -60,7 +62,7 @@ public static SpiDevice Create(SpiConnectionSettings settings) { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - return new Windows10SpiDevice(settings); + return CreateWindows10SpiDevice(settings); } else { @@ -68,6 +70,16 @@ public static SpiDevice Create(SpiConnectionSettings settings) } } + [MethodImpl(MethodImplOptions.NoInlining)] + private static SpiDevice CreateWindows10SpiDevice(SpiConnectionSettings settings) + { + // This wrapper is needed to prevent Mono from loading Windows10SpiDevice + // which causes all fields to be loaded - one of such fields is WinRT type which does not + // exist on Linux which causes TypeLoadException. + // Using NoInlining and no explicit type prevents this from happening. + return new Windows10SpiDevice(settings); + } + /// public void Dispose() {