From f9015f8022c86ec5fab59081e5d0d2f3f1155a1b Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Fri, 6 Dec 2019 21:09:52 +0100 Subject: [PATCH] Codestyling... --- Unosquare.WiringPi/BootstrapWiringPi.cs | 24 +- Unosquare.WiringPi/Enums.cs | 555 ++++---- Unosquare.WiringPi/GpioController.cs | 1133 ++++++++------- Unosquare.WiringPi/GpioPin.Factory.cs | 365 +++-- Unosquare.WiringPi/GpioPin.cs | 1231 ++++++++--------- Unosquare.WiringPi/I2CBus.cs | 134 +- Unosquare.WiringPi/I2CDevice.cs | 357 ++--- Unosquare.WiringPi/Native/Delegates.cs | 21 +- Unosquare.WiringPi/Native/SysCall.cs | 34 +- Unosquare.WiringPi/Native/WiringPi.I2C.cs | 145 +- .../Native/WiringPi.SerialPort.cs | 135 +- Unosquare.WiringPi/Native/WiringPi.Shift.cs | 69 +- Unosquare.WiringPi/Native/WiringPi.SoftPwm.cs | 125 +- Unosquare.WiringPi/Native/WiringPi.Spi.cs | 103 +- Unosquare.WiringPi/Native/WiringPi.cs | 745 +++++----- .../Resources/EmbeddedResources.cs | 115 +- Unosquare.WiringPi/SpiBus.cs | 86 +- Unosquare.WiringPi/SpiChannel.cs | 255 ++-- Unosquare.WiringPi/SystemInfo.cs | 85 +- Unosquare.WiringPi/Threading.cs | 137 +- Unosquare.WiringPi/Timing.cs | 65 +- 21 files changed, 2883 insertions(+), 3036 deletions(-) diff --git a/Unosquare.WiringPi/BootstrapWiringPi.cs b/Unosquare.WiringPi/BootstrapWiringPi.cs index 6c70067..3ac6d24 100644 --- a/Unosquare.WiringPi/BootstrapWiringPi.cs +++ b/Unosquare.WiringPi/BootstrapWiringPi.cs @@ -1,15 +1,17 @@ -namespace Unosquare.WiringPi -{ - using RaspberryIO.Abstractions; - using Swan.DependencyInjection; - - /// - /// Represents the Bootstrap class to extract resources. - /// - /// - public class BootstrapWiringPi : IBootstrap +using System; + +using Swan.DependencyInjection; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// Represents the Bootstrap class to extract resources. + /// + /// + public class BootstrapWiringPi : IBootstrap { - private static readonly object SyncLock = new object(); + private static readonly Object SyncLock = new Object(); /// public void Bootstrap() diff --git a/Unosquare.WiringPi/Enums.cs b/Unosquare.WiringPi/Enums.cs index 5e5c6b3..2d51e11 100644 --- a/Unosquare.WiringPi/Enums.cs +++ b/Unosquare.WiringPi/Enums.cs @@ -1,289 +1,284 @@ -namespace Unosquare.WiringPi -{ - using System; - +using System; + +namespace Unosquare.WiringPi { + /// + /// Defines all the available Wiring Pi Pin Numbers. + /// + public enum WiringPiPin { /// - /// Defines all the available Wiring Pi Pin Numbers. + /// Unknown WiringPi pin. /// - public enum WiringPiPin - { - /// - /// Unknown WiringPi pin. - /// - Unknown = -1, - - /// - /// WiringPi pin 0. - /// - Pin00 = 0, - - /// - /// WiringPi pin 1. - /// - Pin01 = 1, - - /// - /// WiringPi pin 2. - /// - Pin02 = 2, - - /// - /// WiringPi pin 3. - /// - Pin03 = 3, - - /// - /// WiringPi pin 4. - /// - Pin04 = 4, - - /// - /// WiringPi pin 5. - /// - Pin05 = 5, - - /// - /// WiringPi pin 6. - /// - Pin06 = 6, - - /// - /// WiringPi pin 7. - /// - Pin07 = 7, - - /// - /// WiringPi pin 8. - /// - Pin08 = 8, - - /// - /// WiringPi pin 9. - /// - Pin09 = 9, - - /// - /// WiringPi pin 10. - /// - Pin10 = 10, - - /// - /// WiringPi pin 11. - /// - Pin11 = 11, - - /// - /// WiringPi pin 12. - /// - Pin12 = 12, - - /// - /// WiringPi pin 13. - /// - Pin13 = 13, - - /// - /// WiringPi pin 14. - /// - Pin14 = 14, - - /// - /// WiringPi pin 15. - /// - Pin15 = 15, - - /// - /// WiringPi pin 16. - /// - Pin16 = 16, - - /// - /// WiringPi pin 17. - /// - Pin17 = 17, - - /// - /// WiringPi pin 18. - /// - Pin18 = 18, - - /// - /// WiringPi pin 19. - /// - Pin19 = 19, - - /// - /// WiringPi pin 20. - /// - Pin20 = 20, - - /// - /// WiringPi pin 21. - /// - Pin21 = 21, - - /// - /// WiringPi pin 22. - /// - Pin22 = 22, - - /// - /// WiringPi pin 23. - /// - Pin23 = 23, - - /// - /// WiringPi pin 24. - /// - Pin24 = 24, - - /// - /// WiringPi pin 25. - /// - Pin25 = 25, - - /// - /// WiringPi pin 26. - /// - Pin26 = 26, - - /// - /// WiringPi pin 27. - /// - Pin27 = 27, - - /// - /// WiringPi pin 28. - /// - Pin28 = 28, - - /// - /// WiringPi pin 29. - /// - Pin29 = 29, - - /// - /// WiringPi pin 30. - /// - Pin30 = 30, - - /// - /// WiringPi pin 31. - /// - Pin31 = 31, - } - + Unknown = -1, + /// - /// Defines the different pin capabilities. + /// WiringPi pin 0. /// - [Flags] - public enum PinCapability - { - /// - /// General Purpose capability: Digital and Analog Read/Write - /// - GP = 0x01, - - /// - /// General Purpose Clock (not PWM) - /// - GPCLK = 0x02, - - /// - /// i2c data channel - /// - I2CSDA = 0x04, - - /// - /// i2c clock channel - /// - I2CSCL = 0x08, - - /// - /// SPI Master Out, Slave In channel - /// - SPIMOSI = 0x10, - - /// - /// SPI Master In, Slave Out channel - /// - SPIMISO = 0x20, - - /// - /// SPI Clock channel - /// - SPICLK = 0x40, - - /// - /// SPI Chip Select Channel - /// - SPICS = 0x80, - - /// - /// UART Request to Send Channel - /// - UARTRTS = 0x100, - - /// - /// UART Transmit Channel - /// - UARTTXD = 0x200, - - /// - /// UART Receive Channel - /// - UARTRXD = 0x400, - - /// - /// Hardware Pule Width Modulation - /// - PWM = 0x800, - } - + Pin00 = 0, + /// - /// The PWM mode. + /// WiringPi pin 1. /// - public enum PwmMode - { - /// - /// PWM pulses are sent using mark-sign patterns (old school) - /// - MarkSign = 0, - - /// - /// PWM pulses are sent as a balanced signal (default, newer mode) - /// - Balanced = 1, - } - + Pin01 = 1, + /// - /// Defines GPIO controller initialization modes. + /// WiringPi pin 2. /// - internal enum ControllerMode - { - /// - /// The not initialized - /// - NotInitialized, - - /// - /// The direct with wiring pi pins - /// - DirectWithWiringPiPins, - - /// - /// The direct with BCM pins - /// - DirectWithBcmPins, - - /// - /// The direct with header pins - /// - DirectWithHeaderPins, - - /// - /// The file stream with hardware pins - /// - FileStreamWithHardwarePins, - } + Pin02 = 2, + + /// + /// WiringPi pin 3. + /// + Pin03 = 3, + + /// + /// WiringPi pin 4. + /// + Pin04 = 4, + + /// + /// WiringPi pin 5. + /// + Pin05 = 5, + + /// + /// WiringPi pin 6. + /// + Pin06 = 6, + + /// + /// WiringPi pin 7. + /// + Pin07 = 7, + + /// + /// WiringPi pin 8. + /// + Pin08 = 8, + + /// + /// WiringPi pin 9. + /// + Pin09 = 9, + + /// + /// WiringPi pin 10. + /// + Pin10 = 10, + + /// + /// WiringPi pin 11. + /// + Pin11 = 11, + + /// + /// WiringPi pin 12. + /// + Pin12 = 12, + + /// + /// WiringPi pin 13. + /// + Pin13 = 13, + + /// + /// WiringPi pin 14. + /// + Pin14 = 14, + + /// + /// WiringPi pin 15. + /// + Pin15 = 15, + + /// + /// WiringPi pin 16. + /// + Pin16 = 16, + + /// + /// WiringPi pin 17. + /// + Pin17 = 17, + + /// + /// WiringPi pin 18. + /// + Pin18 = 18, + + /// + /// WiringPi pin 19. + /// + Pin19 = 19, + + /// + /// WiringPi pin 20. + /// + Pin20 = 20, + + /// + /// WiringPi pin 21. + /// + Pin21 = 21, + + /// + /// WiringPi pin 22. + /// + Pin22 = 22, + + /// + /// WiringPi pin 23. + /// + Pin23 = 23, + + /// + /// WiringPi pin 24. + /// + Pin24 = 24, + + /// + /// WiringPi pin 25. + /// + Pin25 = 25, + + /// + /// WiringPi pin 26. + /// + Pin26 = 26, + + /// + /// WiringPi pin 27. + /// + Pin27 = 27, + + /// + /// WiringPi pin 28. + /// + Pin28 = 28, + + /// + /// WiringPi pin 29. + /// + Pin29 = 29, + + /// + /// WiringPi pin 30. + /// + Pin30 = 30, + + /// + /// WiringPi pin 31. + /// + Pin31 = 31, + } + + /// + /// Defines the different pin capabilities. + /// + [Flags] + public enum PinCapability { + /// + /// General Purpose capability: Digital and Analog Read/Write + /// + GP = 0x01, + + /// + /// General Purpose Clock (not PWM) + /// + GPCLK = 0x02, + + /// + /// i2c data channel + /// + I2CSDA = 0x04, + + /// + /// i2c clock channel + /// + I2CSCL = 0x08, + + /// + /// SPI Master Out, Slave In channel + /// + SPIMOSI = 0x10, + + /// + /// SPI Master In, Slave Out channel + /// + SPIMISO = 0x20, + + /// + /// SPI Clock channel + /// + SPICLK = 0x40, + + /// + /// SPI Chip Select Channel + /// + SPICS = 0x80, + + /// + /// UART Request to Send Channel + /// + UARTRTS = 0x100, + + /// + /// UART Transmit Channel + /// + UARTTXD = 0x200, + + /// + /// UART Receive Channel + /// + UARTRXD = 0x400, + + /// + /// Hardware Pule Width Modulation + /// + PWM = 0x800, + } + + /// + /// The PWM mode. + /// + public enum PwmMode { + /// + /// PWM pulses are sent using mark-sign patterns (old school) + /// + MarkSign = 0, + + /// + /// PWM pulses are sent as a balanced signal (default, newer mode) + /// + Balanced = 1, + } + + /// + /// Defines GPIO controller initialization modes. + /// + internal enum ControllerMode { + /// + /// The not initialized + /// + NotInitialized, + + /// + /// The direct with wiring pi pins + /// + DirectWithWiringPiPins, + + /// + /// The direct with BCM pins + /// + DirectWithBcmPins, + + /// + /// The direct with header pins + /// + DirectWithHeaderPins, + + /// + /// The file stream with hardware pins + /// + FileStreamWithHardwarePins, + } } diff --git a/Unosquare.WiringPi/GpioController.cs b/Unosquare.WiringPi/GpioController.cs index cc30710..eb4c712 100644 --- a/Unosquare.WiringPi/GpioController.cs +++ b/Unosquare.WiringPi/GpioController.cs @@ -1,582 +1,557 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using Swan; - using System; - using System.Collections; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; - using System.Threading.Tasks; - +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; + +using Swan; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// Represents the Raspberry Pi GPIO controller + /// as an IReadOnlyCollection of GpioPins. + /// + /// Low level operations are accomplished by using the Wiring Pi library. + /// + public sealed class GpioController : IGpioController { + #region Private Declarations + + private const String WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES"; + private static readonly Object SyncRoot = new Object(); + private readonly List _pins; + + #endregion + + #region Constructors and Initialization + /// - /// Represents the Raspberry Pi GPIO controller - /// as an IReadOnlyCollection of GpioPins. - /// - /// Low level operations are accomplished by using the Wiring Pi library. + /// Initializes static members of the class. /// - public sealed class GpioController : IGpioController - { - #region Private Declarations - - private const string WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES"; - private static readonly object SyncRoot = new object(); - private readonly List _pins; - - #endregion - - #region Constructors and Initialization - - /// - /// Initializes static members of the class. - /// - static GpioController() - { - var wiringPiEdgeDetection = new Dictionary - { - {EdgeDetection.FallingEdge, 21}, - {EdgeDetection.RisingEdge, 1}, - {EdgeDetection.FallingAndRisingEdge, 3}, - }; - - WiringPiEdgeDetectionMapping = new ReadOnlyDictionary(wiringPiEdgeDetection); - } - - /// - /// Initializes a new instance of the class. - /// - /// Unable to initialize the GPIO controller. - internal GpioController() - { - if (_pins != null) - return; - - if (IsInitialized == false) - { - var initResult = Initialize(ControllerMode.DirectWithBcmPins); - if (initResult == false) - throw new Exception("Unable to initialize the GPIO controller."); - } - - _pins = new List - { - GpioPin.Pin00.Value, - GpioPin.Pin01.Value, - GpioPin.Pin02.Value, - GpioPin.Pin03.Value, - GpioPin.Pin04.Value, - GpioPin.Pin05.Value, - GpioPin.Pin06.Value, - GpioPin.Pin07.Value, - GpioPin.Pin08.Value, - GpioPin.Pin09.Value, - GpioPin.Pin10.Value, - GpioPin.Pin11.Value, - GpioPin.Pin12.Value, - GpioPin.Pin13.Value, - GpioPin.Pin14.Value, - GpioPin.Pin15.Value, - GpioPin.Pin16.Value, - GpioPin.Pin17.Value, - GpioPin.Pin18.Value, - GpioPin.Pin19.Value, - GpioPin.Pin20.Value, - GpioPin.Pin21.Value, - GpioPin.Pin22.Value, - GpioPin.Pin23.Value, - GpioPin.Pin24.Value, - GpioPin.Pin25.Value, - GpioPin.Pin26.Value, - GpioPin.Pin27.Value, - GpioPin.Pin28.Value, - GpioPin.Pin29.Value, - GpioPin.Pin30.Value, - GpioPin.Pin31.Value, - }; - - var headerP1 = new Dictionary(_pins.Count); - var headerP5 = new Dictionary(_pins.Count); - foreach (var pin in _pins) - { - if (pin.PhysicalPinNumber < 0) - continue; - - var header = pin.Header == GpioHeader.P1 ? headerP1 : headerP5; - header[pin.PhysicalPinNumber] = pin; - } - - HeaderP1 = new ReadOnlyDictionary(headerP1); - HeaderP5 = new ReadOnlyDictionary(headerP5); - } - - /// - /// Determines if the underlying GPIO controller has been initialized properly. - /// - /// - /// true if the controller is properly initialized; otherwise, false. - /// - public static bool IsInitialized - { - get - { - lock (SyncRoot) - { - return Mode != ControllerMode.NotInitialized; - } - } - } - - /// - /// Gets the wiring pi edge detection mapping. - /// - internal static ReadOnlyDictionary WiringPiEdgeDetectionMapping { get; } - - /// - /// - /// Gets the number of registered pins in the controller. - /// - public int Count => Pins.Count; - - /// - /// Gets or sets the initialization mode. - /// - private static ControllerMode Mode { get; set; } = ControllerMode.NotInitialized; - - #endregion - - #region Pin Addressing - - /// - /// Gets the PWM base frequency (in Hz). - /// - public int PwmBaseFrequency => 19200000; - - /// - /// Gets a red-only collection of all pins. - /// - public ReadOnlyCollection Pins => new ReadOnlyCollection(_pins); - - /// - /// Provides all the pins on Header P1 of the Pi as a lookup by physical header pin number. - /// This header is the main header and it is the one commonly used. - /// - public ReadOnlyDictionary HeaderP1 { get; } - - /// - /// Provides all the pins on Header P5 of the Pi as a lookup by physical header pin number. - /// This header is the secondary header and it is rarely used. - /// - public ReadOnlyDictionary HeaderP5 { get; } - - #endregion - - #region Individual Pin Properties - - /// - /// Provides direct access to Pin known as BCM0. - /// - public GpioPin Pin00 => GpioPin.Pin00.Value; - - /// - /// Provides direct access to Pin known as BCM1. - /// - public GpioPin Pin01 => GpioPin.Pin01.Value; - - /// - /// Provides direct access to Pin known as BCM2. - /// - public GpioPin Pin02 => GpioPin.Pin02.Value; - - /// - /// Provides direct access to Pin known as BCM3. - /// - public GpioPin Pin03 => GpioPin.Pin03.Value; - - /// - /// Provides direct access to Pin known as BCM4. - /// - public GpioPin Pin04 => GpioPin.Pin04.Value; - - /// - /// Provides direct access to Pin known as BCM5. - /// - public GpioPin Pin05 => GpioPin.Pin05.Value; - - /// - /// Provides direct access to Pin known as BCM6. - /// - public GpioPin Pin06 => GpioPin.Pin06.Value; - - /// - /// Provides direct access to Pin known as BCM7. - /// - public GpioPin Pin07 => GpioPin.Pin07.Value; - - /// - /// Provides direct access to Pin known as BCM8. - /// - public GpioPin Pin08 => GpioPin.Pin08.Value; - - /// - /// Provides direct access to Pin known as BCM9. - /// - public GpioPin Pin09 => GpioPin.Pin09.Value; - - /// - /// Provides direct access to Pin known as BCM10. - /// - public GpioPin Pin10 => GpioPin.Pin10.Value; - - /// - /// Provides direct access to Pin known as BCM11. - /// - public GpioPin Pin11 => GpioPin.Pin11.Value; - - /// - /// Provides direct access to Pin known as BCM12. - /// - public GpioPin Pin12 => GpioPin.Pin12.Value; - - /// - /// Provides direct access to Pin known as BCM13. - /// - public GpioPin Pin13 => GpioPin.Pin13.Value; - - /// - /// Provides direct access to Pin known as BCM14. - /// - public GpioPin Pin14 => GpioPin.Pin14.Value; - - /// - /// Provides direct access to Pin known as BCM15. - /// - public GpioPin Pin15 => GpioPin.Pin15.Value; - - /// - /// Provides direct access to Pin known as BCM16. - /// - public GpioPin Pin16 => GpioPin.Pin16.Value; - - /// - /// Provides direct access to Pin known as BCM17. - /// - public GpioPin Pin17 => GpioPin.Pin17.Value; - - /// - /// Provides direct access to Pin known as BCM18. - /// - public GpioPin Pin18 => GpioPin.Pin18.Value; - - /// - /// Provides direct access to Pin known as BCM19. - /// - public GpioPin Pin19 => GpioPin.Pin19.Value; - - /// - /// Provides direct access to Pin known as BCM20. - /// - public GpioPin Pin20 => GpioPin.Pin20.Value; - - /// - /// Provides direct access to Pin known as BCM21. - /// - public GpioPin Pin21 => GpioPin.Pin21.Value; - - /// - /// Provides direct access to Pin known as BCM22. - /// - public GpioPin Pin22 => GpioPin.Pin22.Value; - - /// - /// Provides direct access to Pin known as BCM23. - /// - public GpioPin Pin23 => GpioPin.Pin23.Value; - - /// - /// Provides direct access to Pin known as BCM24. - /// - public GpioPin Pin24 => GpioPin.Pin24.Value; - - /// - /// Provides direct access to Pin known as BCM25. - /// - public GpioPin Pin25 => GpioPin.Pin25.Value; - - /// - /// Provides direct access to Pin known as BCM26. - /// - public GpioPin Pin26 => GpioPin.Pin26.Value; - - /// - /// Provides direct access to Pin known as BCM27. - /// - public GpioPin Pin27 => GpioPin.Pin27.Value; - - /// - /// Provides direct access to Pin known as BCM28 (available on Header P5). - /// - public GpioPin Pin28 => GpioPin.Pin28.Value; - - /// - /// Provides direct access to Pin known as BCM29 (available on Header P5). - /// - public GpioPin Pin29 => GpioPin.Pin29.Value; - - /// - /// Provides direct access to Pin known as BCM30 (available on Header P5). - /// - public GpioPin Pin30 => GpioPin.Pin30.Value; - - /// - /// Provides direct access to Pin known as BCM31 (available on Header P5). - /// - public GpioPin Pin31 => GpioPin.Pin31.Value; - - #endregion - - #region Indexers - - /// - public IGpioPin this[BcmPin bcmPin] => Pins[(int)bcmPin]; - - /// - public IGpioPin this[int bcmPinNumber] - { - get - { - if (!Enum.IsDefined(typeof(BcmPin), bcmPinNumber)) - throw new IndexOutOfRangeException($"Pin {bcmPinNumber} is not registered in the GPIO controller."); - - return Pins[bcmPinNumber]; - } - } - - /// - public IGpioPin this[P1 pinNumber] => HeaderP1[(int)pinNumber]; - - /// - public IGpioPin this[P5 pinNumber] => HeaderP5[(int)pinNumber]; - - /// - /// Gets the with the specified Wiring Pi pin number. - /// - /// - /// The . - /// - /// The pin number. - /// A reference to the GPIO pin. - public GpioPin this[WiringPiPin pinNumber] - { - get - { - if (pinNumber == WiringPiPin.Unknown) - throw new InvalidOperationException("You can not get an unknown WiringPi pin."); - - return Pins.First(p => p.WiringPiPinNumber == pinNumber); - } - } - - #endregion - - #region Pin Group Methods (Read, Write, Pad Drive) - - /// - /// This sets the “strength” of the pad drivers for a particular group of pins. - /// There are 3 groups of pins and the drive strength is from 0 to 7. - /// Do not use this unless you know what you are doing. - /// - /// The group. - /// The value. - public void SetPadDrive(int group, int value) - { - lock (SyncRoot) - { - WiringPi.SetPadDrive(group, value); - } - } - - /// - /// This sets the “strength” of the pad drivers for a particular group of pins. - /// There are 3 groups of pins and the drive strength is from 0 to 7. - /// Do not use this unless you know what you are doing. - /// - /// The group. - /// The value. - /// The awaitable task. - public Task SetPadDriveAsync(int group, int value) => - Task.Run(() => SetPadDrive(group, value)); - - /// - /// This writes the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to set all 8 bits at once to a particular value, - /// although it still takes two write operations to the Pi’s GPIO hardware. - /// - /// The value. - /// PinMode. - public void WriteByte(byte value) - { - lock (SyncRoot) - { - if (this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output)) - { - throw new InvalidOperationException( - $"All first 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Output}"); - } - - WiringPi.DigitalWriteByte(value); - } - } - - /// - /// This writes the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to set all 8 bits at once to a particular value, - /// although it still takes two write operations to the Pi’s GPIO hardware. - /// - /// The value. - /// The awaitable task. - public Task WriteByteAsync(byte value) => - Task.Run(() => WriteByte(value)); - - /// - /// This reads the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to get all 8 bits at once to a particular value. - /// Please note this function is undocumented and unsupported. - /// - /// A byte from the GPIO. - /// PinMode. - public byte ReadByte() - { - lock (SyncRoot) - { - if (this.Skip(0).Take(8).Any(p => - p.PinMode != GpioPinDriveMode.Input && p.PinMode != GpioPinDriveMode.Output)) - { - throw new InvalidOperationException( - $"All first 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); - } - - return (byte)WiringPi.DigitalReadByte(); - } - } - - /// - /// This reads the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to get all 8 bits at once to a particular value. - /// Please note this function is undocumented and unsupported. - /// - /// A byte from the GPIO. - public Task ReadByteAsync() => - Task.Run(ReadByte); - - #endregion - - #region IReadOnlyCollection Implementation - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() => Pins.GetEnumerator(); - - /// - IEnumerator IEnumerable.GetEnumerator() => Pins.GetEnumerator(); - - /// - IEnumerator IEnumerable.GetEnumerator() => Pins.GetEnumerator(); - - #endregion - - #region Helper and Init Methods - - /// - /// Converts the Wirings Pi pin number to the BCM pin number. - /// - /// The wiring pi pin number. - /// The converted pin. - internal static int WiringPiToBcmPinNumber(int wiringPiPinNumber) - { - lock (SyncRoot) - { - return WiringPi.WpiPinToGpio(wiringPiPinNumber); - } - } - - /// - /// Converts the Physical (Header) pin number to BCM pin number. - /// - /// The header pin number. - /// The converted pin. - internal static int HaderToBcmPinNumber(int headerPinNumber) - { - lock (SyncRoot) - { - return WiringPi.PhysPinToGpio(headerPinNumber); - } - } - - /// - /// Initializes the controller given the initialization mode and pin numbering scheme. - /// - /// The mode. - /// True when successful. - /// - /// This library does not support the platform. - /// - /// Library was already Initialized. - /// The init mode is invalid. - private bool Initialize(ControllerMode mode) - { - if (SwanRuntime.OS != Swan.OperatingSystem.Unix) - throw new PlatformNotSupportedException("This library does not support the platform"); - - lock (SyncRoot) - { - if (IsInitialized) - throw new InvalidOperationException($"Cannot call {nameof(Initialize)} more than once."); - - Environment.SetEnvironmentVariable(WiringPiCodesEnvironmentVariable, "1"); - int setupResult; - - switch (mode) - { - case ControllerMode.DirectWithWiringPiPins: - { - setupResult = WiringPi.WiringPiSetup(); - break; - } - - case ControllerMode.DirectWithBcmPins: - { - setupResult = WiringPi.WiringPiSetupGpio(); - break; - } - - case ControllerMode.DirectWithHeaderPins: - { - setupResult = WiringPi.WiringPiSetupPhys(); - break; - } - - case ControllerMode.FileStreamWithHardwarePins: - { - setupResult = WiringPi.WiringPiSetupSys(); - break; - } - - default: - { - throw new ArgumentException($"'{mode}' is not a valid initialization mode."); - } - } - - Mode = setupResult == 0 ? mode : ControllerMode.NotInitialized; - return IsInitialized; - } - } - #endregion - - } + static GpioController() { + Dictionary wiringPiEdgeDetection = new Dictionary + { + {EdgeDetection.FallingEdge, 21}, + {EdgeDetection.RisingEdge, 1}, + {EdgeDetection.FallingAndRisingEdge, 3} + }; + + WiringPiEdgeDetectionMapping = new ReadOnlyDictionary(wiringPiEdgeDetection); + } + + /// + /// Initializes a new instance of the class. + /// + /// Unable to initialize the GPIO controller. + internal GpioController() { + if(this._pins != null) { + return; + } + + if(IsInitialized == false) { + Boolean initResult = this.Initialize(ControllerMode.DirectWithBcmPins); + if(initResult == false) { + throw new Exception("Unable to initialize the GPIO controller."); + } + } + + this._pins = new List { + GpioPin.Pin00.Value, + GpioPin.Pin01.Value, + GpioPin.Pin02.Value, + GpioPin.Pin03.Value, + GpioPin.Pin04.Value, + GpioPin.Pin05.Value, + GpioPin.Pin06.Value, + GpioPin.Pin07.Value, + GpioPin.Pin08.Value, + GpioPin.Pin09.Value, + GpioPin.Pin10.Value, + GpioPin.Pin11.Value, + GpioPin.Pin12.Value, + GpioPin.Pin13.Value, + GpioPin.Pin14.Value, + GpioPin.Pin15.Value, + GpioPin.Pin16.Value, + GpioPin.Pin17.Value, + GpioPin.Pin18.Value, + GpioPin.Pin19.Value, + GpioPin.Pin20.Value, + GpioPin.Pin21.Value, + GpioPin.Pin22.Value, + GpioPin.Pin23.Value, + GpioPin.Pin24.Value, + GpioPin.Pin25.Value, + GpioPin.Pin26.Value, + GpioPin.Pin27.Value, + GpioPin.Pin28.Value, + GpioPin.Pin29.Value, + GpioPin.Pin30.Value, + GpioPin.Pin31.Value, + }; + + Dictionary headerP1 = new Dictionary(this._pins.Count); + Dictionary headerP5 = new Dictionary(this._pins.Count); + foreach(GpioPin pin in this._pins) { + if(pin.PhysicalPinNumber < 0) { + continue; + } + + Dictionary header = pin.Header == GpioHeader.P1 ? headerP1 : headerP5; + header[pin.PhysicalPinNumber] = pin; + } + + this.HeaderP1 = new ReadOnlyDictionary(headerP1); + this.HeaderP5 = new ReadOnlyDictionary(headerP5); + } + + /// + /// Determines if the underlying GPIO controller has been initialized properly. + /// + /// + /// true if the controller is properly initialized; otherwise, false. + /// + public static Boolean IsInitialized { + get { + lock(SyncRoot) { + return Mode != ControllerMode.NotInitialized; + } + } + } + + /// + /// Gets the wiring pi edge detection mapping. + /// + internal static ReadOnlyDictionary WiringPiEdgeDetectionMapping { + get; + } + + /// + /// + /// Gets the number of registered pins in the controller. + /// + public Int32 Count => this.Pins.Count; + + /// + /// Gets or sets the initialization mode. + /// + private static ControllerMode Mode { get; set; } = ControllerMode.NotInitialized; + + #endregion + + #region Pin Addressing + + /// + /// Gets the PWM base frequency (in Hz). + /// + public Int32 PwmBaseFrequency => 19200000; + + /// + /// Gets a red-only collection of all pins. + /// + public ReadOnlyCollection Pins => new ReadOnlyCollection(this._pins); + + /// + /// Provides all the pins on Header P1 of the Pi as a lookup by physical header pin number. + /// This header is the main header and it is the one commonly used. + /// + public ReadOnlyDictionary HeaderP1 { + get; + } + + /// + /// Provides all the pins on Header P5 of the Pi as a lookup by physical header pin number. + /// This header is the secondary header and it is rarely used. + /// + public ReadOnlyDictionary HeaderP5 { + get; + } + + #endregion + + #region Individual Pin Properties + + /// + /// Provides direct access to Pin known as BCM0. + /// + public GpioPin Pin00 => GpioPin.Pin00.Value; + + /// + /// Provides direct access to Pin known as BCM1. + /// + public GpioPin Pin01 => GpioPin.Pin01.Value; + + /// + /// Provides direct access to Pin known as BCM2. + /// + public GpioPin Pin02 => GpioPin.Pin02.Value; + + /// + /// Provides direct access to Pin known as BCM3. + /// + public GpioPin Pin03 => GpioPin.Pin03.Value; + + /// + /// Provides direct access to Pin known as BCM4. + /// + public GpioPin Pin04 => GpioPin.Pin04.Value; + + /// + /// Provides direct access to Pin known as BCM5. + /// + public GpioPin Pin05 => GpioPin.Pin05.Value; + + /// + /// Provides direct access to Pin known as BCM6. + /// + public GpioPin Pin06 => GpioPin.Pin06.Value; + + /// + /// Provides direct access to Pin known as BCM7. + /// + public GpioPin Pin07 => GpioPin.Pin07.Value; + + /// + /// Provides direct access to Pin known as BCM8. + /// + public GpioPin Pin08 => GpioPin.Pin08.Value; + + /// + /// Provides direct access to Pin known as BCM9. + /// + public GpioPin Pin09 => GpioPin.Pin09.Value; + + /// + /// Provides direct access to Pin known as BCM10. + /// + public GpioPin Pin10 => GpioPin.Pin10.Value; + + /// + /// Provides direct access to Pin known as BCM11. + /// + public GpioPin Pin11 => GpioPin.Pin11.Value; + + /// + /// Provides direct access to Pin known as BCM12. + /// + public GpioPin Pin12 => GpioPin.Pin12.Value; + + /// + /// Provides direct access to Pin known as BCM13. + /// + public GpioPin Pin13 => GpioPin.Pin13.Value; + + /// + /// Provides direct access to Pin known as BCM14. + /// + public GpioPin Pin14 => GpioPin.Pin14.Value; + + /// + /// Provides direct access to Pin known as BCM15. + /// + public GpioPin Pin15 => GpioPin.Pin15.Value; + + /// + /// Provides direct access to Pin known as BCM16. + /// + public GpioPin Pin16 => GpioPin.Pin16.Value; + + /// + /// Provides direct access to Pin known as BCM17. + /// + public GpioPin Pin17 => GpioPin.Pin17.Value; + + /// + /// Provides direct access to Pin known as BCM18. + /// + public GpioPin Pin18 => GpioPin.Pin18.Value; + + /// + /// Provides direct access to Pin known as BCM19. + /// + public GpioPin Pin19 => GpioPin.Pin19.Value; + + /// + /// Provides direct access to Pin known as BCM20. + /// + public GpioPin Pin20 => GpioPin.Pin20.Value; + + /// + /// Provides direct access to Pin known as BCM21. + /// + public GpioPin Pin21 => GpioPin.Pin21.Value; + + /// + /// Provides direct access to Pin known as BCM22. + /// + public GpioPin Pin22 => GpioPin.Pin22.Value; + + /// + /// Provides direct access to Pin known as BCM23. + /// + public GpioPin Pin23 => GpioPin.Pin23.Value; + + /// + /// Provides direct access to Pin known as BCM24. + /// + public GpioPin Pin24 => GpioPin.Pin24.Value; + + /// + /// Provides direct access to Pin known as BCM25. + /// + public GpioPin Pin25 => GpioPin.Pin25.Value; + + /// + /// Provides direct access to Pin known as BCM26. + /// + public GpioPin Pin26 => GpioPin.Pin26.Value; + + /// + /// Provides direct access to Pin known as BCM27. + /// + public GpioPin Pin27 => GpioPin.Pin27.Value; + + /// + /// Provides direct access to Pin known as BCM28 (available on Header P5). + /// + public GpioPin Pin28 => GpioPin.Pin28.Value; + + /// + /// Provides direct access to Pin known as BCM29 (available on Header P5). + /// + public GpioPin Pin29 => GpioPin.Pin29.Value; + + /// + /// Provides direct access to Pin known as BCM30 (available on Header P5). + /// + public GpioPin Pin30 => GpioPin.Pin30.Value; + + /// + /// Provides direct access to Pin known as BCM31 (available on Header P5). + /// + public GpioPin Pin31 => GpioPin.Pin31.Value; + + #endregion + + #region Indexers + + /// + public IGpioPin this[BcmPin bcmPin] => this.Pins[(Int32)bcmPin]; + + /// + public IGpioPin this[Int32 bcmPinNumber] { + get { + if(!Enum.IsDefined(typeof(BcmPin), bcmPinNumber)) { + throw new IndexOutOfRangeException($"Pin {bcmPinNumber} is not registered in the GPIO controller."); + } + + return this.Pins[bcmPinNumber]; + } + } + + /// + public IGpioPin this[P1 pinNumber] => this.HeaderP1[(Int32)pinNumber]; + + /// + public IGpioPin this[P5 pinNumber] => this.HeaderP5[(Int32)pinNumber]; + + /// + /// Gets the with the specified Wiring Pi pin number. + /// + /// + /// The . + /// + /// The pin number. + /// A reference to the GPIO pin. + public GpioPin this[WiringPiPin pinNumber] { + get { + if(pinNumber == WiringPiPin.Unknown) { + throw new InvalidOperationException("You can not get an unknown WiringPi pin."); + } + + return this.Pins.First(p => p.WiringPiPinNumber == pinNumber); + } + } + + #endregion + + #region Pin Group Methods (Read, Write, Pad Drive) + + /// + /// This sets the “strength” of the pad drivers for a particular group of pins. + /// There are 3 groups of pins and the drive strength is from 0 to 7. + /// Do not use this unless you know what you are doing. + /// + /// The group. + /// The value. + public void SetPadDrive(Int32 group, Int32 value) { + lock(SyncRoot) { + _ = Native.WiringPi.SetPadDrive(group, value); + } + } + + /// + /// This sets the “strength” of the pad drivers for a particular group of pins. + /// There are 3 groups of pins and the drive strength is from 0 to 7. + /// Do not use this unless you know what you are doing. + /// + /// The group. + /// The value. + /// The awaitable task. + public Task SetPadDriveAsync(Int32 group, Int32 value) => Task.Run(() => this.SetPadDrive(group, value)); + + /// + /// This writes the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to set all 8 bits at once to a particular value, + /// although it still takes two write operations to the Pi’s GPIO hardware. + /// + /// The value. + /// PinMode. + public void WriteByte(Byte value) { + lock(SyncRoot) { + if(this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output)) { + throw new InvalidOperationException($"All first 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Output}"); + } + + Native.WiringPi.DigitalWriteByte(value); + } + } + + /// + /// This writes the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to set all 8 bits at once to a particular value, + /// although it still takes two write operations to the Pi’s GPIO hardware. + /// + /// The value. + /// The awaitable task. + public Task WriteByteAsync(Byte value) => Task.Run(() => this.WriteByte(value)); + + /// + /// This reads the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to get all 8 bits at once to a particular value. + /// Please note this function is undocumented and unsupported. + /// + /// A byte from the GPIO. + /// PinMode. + public Byte ReadByte() { + lock(SyncRoot) { + if(this.Skip(0).Take(8).Any(p => + p.PinMode != GpioPinDriveMode.Input && p.PinMode != GpioPinDriveMode.Output)) { + throw new InvalidOperationException($"All first 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); + } + + return (Byte)Native.WiringPi.DigitalReadByte(); + } + } + + /// + /// This reads the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to get all 8 bits at once to a particular value. + /// Please note this function is undocumented and unsupported. + /// + /// A byte from the GPIO. + public Task ReadByteAsync() => Task.Run(this.ReadByte); + + #endregion + + #region IReadOnlyCollection Implementation + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() => this.Pins.GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() => this.Pins.GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() => this.Pins.GetEnumerator(); + + #endregion + + #region Helper and Init Methods + + /// + /// Converts the Wirings Pi pin number to the BCM pin number. + /// + /// The wiring pi pin number. + /// The converted pin. + internal static Int32 WiringPiToBcmPinNumber(Int32 wiringPiPinNumber) { + lock(SyncRoot) { + return Native.WiringPi.WpiPinToGpio(wiringPiPinNumber); + } + } + + /// + /// Converts the Physical (Header) pin number to BCM pin number. + /// + /// The header pin number. + /// The converted pin. + internal static Int32 HaderToBcmPinNumber(Int32 headerPinNumber) { + lock(SyncRoot) { + return Native.WiringPi.PhysPinToGpio(headerPinNumber); + } + } + + /// + /// Initializes the controller given the initialization mode and pin numbering scheme. + /// + /// The mode. + /// True when successful. + /// + /// This library does not support the platform. + /// + /// Library was already Initialized. + /// The init mode is invalid. + private Boolean Initialize(ControllerMode mode) { + if(SwanRuntime.OS != Swan.OperatingSystem.Unix) { + throw new PlatformNotSupportedException("This library does not support the platform"); + } + + lock(SyncRoot) { + if(IsInitialized) { + throw new InvalidOperationException($"Cannot call {nameof(Initialize)} more than once."); + } + + Environment.SetEnvironmentVariable(WiringPiCodesEnvironmentVariable, "1"); + Int32 setupResult; + + switch(mode) { + case ControllerMode.DirectWithWiringPiPins: { + setupResult = Native.WiringPi.WiringPiSetup(); + break; + } + + case ControllerMode.DirectWithBcmPins: { + setupResult = Native.WiringPi.WiringPiSetupGpio(); + break; + } + + case ControllerMode.DirectWithHeaderPins: { + setupResult = Native.WiringPi.WiringPiSetupPhys(); + break; + } + + case ControllerMode.FileStreamWithHardwarePins: { + setupResult = Native.WiringPi.WiringPiSetupSys(); + break; + } + + default: { + throw new ArgumentException($"'{mode}' is not a valid initialization mode."); + } + } + + Mode = setupResult == 0 ? mode : ControllerMode.NotInitialized; + return IsInitialized; + } + } + #endregion + + } } diff --git a/Unosquare.WiringPi/GpioPin.Factory.cs b/Unosquare.WiringPi/GpioPin.Factory.cs index 2cffb47..f061d16 100644 --- a/Unosquare.WiringPi/GpioPin.Factory.cs +++ b/Unosquare.WiringPi/GpioPin.Factory.cs @@ -1,200 +1,167 @@ -namespace Unosquare.WiringPi -{ - using RaspberryIO.Abstractions; - using System; - - public partial class GpioPin - { - internal static readonly Lazy Pin00 = new Lazy(() => new GpioPin(BcmPin.Gpio00) - { - Capabilities = PinCapability.GP | PinCapability.I2CSDA, - Name = $"BCM 0 {(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? "(SDA)" : "(ID_SD)")}", - }); - - internal static readonly Lazy Pin01 = new Lazy(() => new GpioPin(BcmPin.Gpio01) - { - Capabilities = PinCapability.GP | PinCapability.I2CSCL, - Name = $"BCM 1 {(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? "(SCL)" : "(ID_SC)")}", - }); - - internal static readonly Lazy Pin02 = new Lazy(() => new GpioPin(BcmPin.Gpio02) - { - Capabilities = PinCapability.GP | PinCapability.I2CSDA, - Name = "BCM 2 (SDA)", - }); - - internal static readonly Lazy Pin03 = new Lazy(() => new GpioPin(BcmPin.Gpio03) - { - Capabilities = PinCapability.GP | PinCapability.I2CSCL, - Name = "BCM 3 (SCL)", - }); - - internal static readonly Lazy Pin04 = new Lazy(() => new GpioPin(BcmPin.Gpio04) - { - Capabilities = PinCapability.GP | PinCapability.GPCLK, - Name = "BCM 4 (GPCLK0)", - }); - - internal static readonly Lazy Pin05 = new Lazy(() => new GpioPin(BcmPin.Gpio05) - { - Capabilities = PinCapability.GP, - Name = "BCM 5", - }); - - internal static readonly Lazy Pin06 = new Lazy(() => new GpioPin(BcmPin.Gpio06) - { - Capabilities = PinCapability.GP, - Name = "BCM 6", - }); - - internal static readonly Lazy Pin07 = new Lazy(() => new GpioPin(BcmPin.Gpio07) - { - Capabilities = PinCapability.GP | PinCapability.SPICS, - Name = "BCM 7 (CE1)", - }); - - internal static readonly Lazy Pin08 = new Lazy(() => new GpioPin(BcmPin.Gpio08) - { - Capabilities = PinCapability.GP | PinCapability.SPICS, - Name = "BCM 8 (CE0)", - }); - - internal static readonly Lazy Pin09 = new Lazy(() => new GpioPin(BcmPin.Gpio09) - { - Capabilities = PinCapability.GP | PinCapability.SPIMISO, - Name = "BCM 9 (MISO)", - }); - - internal static readonly Lazy Pin10 = new Lazy(() => new GpioPin(BcmPin.Gpio10) - { - Capabilities = PinCapability.GP | PinCapability.SPIMOSI, - Name = "BCM 10 (MOSI)", - }); - - internal static readonly Lazy Pin11 = new Lazy(() => new GpioPin(BcmPin.Gpio11) - { - Capabilities = PinCapability.GP | PinCapability.SPICLK, - Name = "BCM 11 (SCLCK)", - }); - - internal static readonly Lazy Pin12 = new Lazy(() => new GpioPin(BcmPin.Gpio12) - { - Capabilities = PinCapability.GP | PinCapability.PWM, - Name = "BCM 12 (PWM0)", - }); - - internal static readonly Lazy Pin13 = new Lazy(() => new GpioPin(BcmPin.Gpio13) - { - Capabilities = PinCapability.GP | PinCapability.PWM, - Name = "BCM 13 (PWM1)", - }); - - internal static readonly Lazy Pin14 = new Lazy(() => new GpioPin(BcmPin.Gpio14) - { - Capabilities = PinCapability.UARTTXD, - Name = "BCM 14 (TXD)", - }); - - internal static readonly Lazy Pin15 = new Lazy(() => new GpioPin(BcmPin.Gpio15) - { - Capabilities = PinCapability.UARTRXD, - Name = "BCM 15 (RXD)", - }); - - internal static readonly Lazy Pin16 = new Lazy(() => new GpioPin(BcmPin.Gpio16) - { - Capabilities = PinCapability.GP, - Name = "BCM 16", - }); - - internal static readonly Lazy Pin17 = new Lazy(() => new GpioPin(BcmPin.Gpio17) - { - Capabilities = PinCapability.GP | PinCapability.UARTRTS, - Name = "BCM 17", - }); - - internal static readonly Lazy Pin18 = new Lazy(() => new GpioPin(BcmPin.Gpio18) - { - Capabilities = PinCapability.GP | PinCapability.PWM, - Name = "BCM 18 (PWM0)", - }); - - internal static readonly Lazy Pin19 = new Lazy(() => new GpioPin(BcmPin.Gpio19) - { - Capabilities = PinCapability.GP | PinCapability.PWM | PinCapability.SPIMISO, - Name = "BCM 19 (MISO)", - }); - - internal static readonly Lazy Pin20 = new Lazy(() => new GpioPin(BcmPin.Gpio20) - { - Capabilities = PinCapability.GP | PinCapability.SPIMOSI, - Name = "BCM 20 (MOSI)", - }); - - internal static readonly Lazy Pin21 = new Lazy(() => new GpioPin(BcmPin.Gpio21) - { - Capabilities = PinCapability.GP | PinCapability.SPICLK, - Name = $"BCM 21{(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? string.Empty : " (SCLK)")}", - }); - - internal static readonly Lazy Pin22 = new Lazy(() => new GpioPin(BcmPin.Gpio22) - { - Capabilities = PinCapability.GP, - Name = "BCM 22", - }); - - internal static readonly Lazy Pin23 = new Lazy(() => new GpioPin(BcmPin.Gpio23) - { - Capabilities = PinCapability.GP, - Name = "BCM 23", - }); - - internal static readonly Lazy Pin24 = new Lazy(() => new GpioPin(BcmPin.Gpio24) - { - Capabilities = PinCapability.GP, - Name = "BCM 24", - }); - - internal static readonly Lazy Pin25 = new Lazy(() => new GpioPin(BcmPin.Gpio25) - { - Capabilities = PinCapability.GP, - Name = "BCM 25", - }); - - internal static readonly Lazy Pin26 = new Lazy(() => new GpioPin(BcmPin.Gpio26) - { - Capabilities = PinCapability.GP, - Name = "BCM 26", - }); - - internal static readonly Lazy Pin27 = new Lazy(() => new GpioPin(BcmPin.Gpio27) - { - Capabilities = PinCapability.GP, - Name = "BCM 27", - }); - - internal static readonly Lazy Pin28 = new Lazy(() => new GpioPin(BcmPin.Gpio28) - { - Capabilities = PinCapability.GP | PinCapability.I2CSDA, - Name = "BCM 28 (SDA)", - }); - - internal static readonly Lazy Pin29 = new Lazy(() => new GpioPin(BcmPin.Gpio29) - { - Capabilities = PinCapability.GP | PinCapability.I2CSCL, - Name = "BCM 29 (SCL)", - }); - - internal static readonly Lazy Pin30 = new Lazy(() => new GpioPin(BcmPin.Gpio30) - { - Capabilities = PinCapability.GP, - Name = "BCM 30", - }); - - internal static readonly Lazy Pin31 = new Lazy(() => new GpioPin(BcmPin.Gpio31) - { - Capabilities = PinCapability.GP, - Name = "BCM 31", - }); - } +using System; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + public partial class GpioPin { + internal static readonly Lazy Pin00 = new Lazy(() => new GpioPin(BcmPin.Gpio00) { + Capabilities = PinCapability.GP | PinCapability.I2CSDA, + Name = $"BCM 0 {(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? "(SDA)" : "(ID_SD)")}", + }); + + internal static readonly Lazy Pin01 = new Lazy(() => new GpioPin(BcmPin.Gpio01) { + Capabilities = PinCapability.GP | PinCapability.I2CSCL, + Name = $"BCM 1 {(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? "(SCL)" : "(ID_SC)")}", + }); + + internal static readonly Lazy Pin02 = new Lazy(() => new GpioPin(BcmPin.Gpio02) { + Capabilities = PinCapability.GP | PinCapability.I2CSDA, + Name = "BCM 2 (SDA)", + }); + + internal static readonly Lazy Pin03 = new Lazy(() => new GpioPin(BcmPin.Gpio03) { + Capabilities = PinCapability.GP | PinCapability.I2CSCL, + Name = "BCM 3 (SCL)", + }); + + internal static readonly Lazy Pin04 = new Lazy(() => new GpioPin(BcmPin.Gpio04) { + Capabilities = PinCapability.GP | PinCapability.GPCLK, + Name = "BCM 4 (GPCLK0)", + }); + + internal static readonly Lazy Pin05 = new Lazy(() => new GpioPin(BcmPin.Gpio05) { + Capabilities = PinCapability.GP, + Name = "BCM 5", + }); + + internal static readonly Lazy Pin06 = new Lazy(() => new GpioPin(BcmPin.Gpio06) { + Capabilities = PinCapability.GP, + Name = "BCM 6", + }); + + internal static readonly Lazy Pin07 = new Lazy(() => new GpioPin(BcmPin.Gpio07) { + Capabilities = PinCapability.GP | PinCapability.SPICS, + Name = "BCM 7 (CE1)", + }); + + internal static readonly Lazy Pin08 = new Lazy(() => new GpioPin(BcmPin.Gpio08) { + Capabilities = PinCapability.GP | PinCapability.SPICS, + Name = "BCM 8 (CE0)", + }); + + internal static readonly Lazy Pin09 = new Lazy(() => new GpioPin(BcmPin.Gpio09) { + Capabilities = PinCapability.GP | PinCapability.SPIMISO, + Name = "BCM 9 (MISO)", + }); + + internal static readonly Lazy Pin10 = new Lazy(() => new GpioPin(BcmPin.Gpio10) { + Capabilities = PinCapability.GP | PinCapability.SPIMOSI, + Name = "BCM 10 (MOSI)", + }); + + internal static readonly Lazy Pin11 = new Lazy(() => new GpioPin(BcmPin.Gpio11) { + Capabilities = PinCapability.GP | PinCapability.SPICLK, + Name = "BCM 11 (SCLCK)", + }); + + internal static readonly Lazy Pin12 = new Lazy(() => new GpioPin(BcmPin.Gpio12) { + Capabilities = PinCapability.GP | PinCapability.PWM, + Name = "BCM 12 (PWM0)", + }); + + internal static readonly Lazy Pin13 = new Lazy(() => new GpioPin(BcmPin.Gpio13) { + Capabilities = PinCapability.GP | PinCapability.PWM, + Name = "BCM 13 (PWM1)", + }); + + internal static readonly Lazy Pin14 = new Lazy(() => new GpioPin(BcmPin.Gpio14) { + Capabilities = PinCapability.UARTTXD, + Name = "BCM 14 (TXD)", + }); + + internal static readonly Lazy Pin15 = new Lazy(() => new GpioPin(BcmPin.Gpio15) { + Capabilities = PinCapability.UARTRXD, + Name = "BCM 15 (RXD)", + }); + + internal static readonly Lazy Pin16 = new Lazy(() => new GpioPin(BcmPin.Gpio16) { + Capabilities = PinCapability.GP, + Name = "BCM 16", + }); + + internal static readonly Lazy Pin17 = new Lazy(() => new GpioPin(BcmPin.Gpio17) { + Capabilities = PinCapability.GP | PinCapability.UARTRTS, + Name = "BCM 17", + }); + + internal static readonly Lazy Pin18 = new Lazy(() => new GpioPin(BcmPin.Gpio18) { + Capabilities = PinCapability.GP | PinCapability.PWM, + Name = "BCM 18 (PWM0)", + }); + + internal static readonly Lazy Pin19 = new Lazy(() => new GpioPin(BcmPin.Gpio19) { + Capabilities = PinCapability.GP | PinCapability.PWM | PinCapability.SPIMISO, + Name = "BCM 19 (MISO)", + }); + + internal static readonly Lazy Pin20 = new Lazy(() => new GpioPin(BcmPin.Gpio20) { + Capabilities = PinCapability.GP | PinCapability.SPIMOSI, + Name = "BCM 20 (MOSI)", + }); + + internal static readonly Lazy Pin21 = new Lazy(() => new GpioPin(BcmPin.Gpio21) { + Capabilities = PinCapability.GP | PinCapability.SPICLK, + Name = $"BCM 21{(SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? String.Empty : " (SCLK)")}", + }); + + internal static readonly Lazy Pin22 = new Lazy(() => new GpioPin(BcmPin.Gpio22) { + Capabilities = PinCapability.GP, + Name = "BCM 22", + }); + + internal static readonly Lazy Pin23 = new Lazy(() => new GpioPin(BcmPin.Gpio23) { + Capabilities = PinCapability.GP, + Name = "BCM 23", + }); + + internal static readonly Lazy Pin24 = new Lazy(() => new GpioPin(BcmPin.Gpio24) { + Capabilities = PinCapability.GP, + Name = "BCM 24", + }); + + internal static readonly Lazy Pin25 = new Lazy(() => new GpioPin(BcmPin.Gpio25) { + Capabilities = PinCapability.GP, + Name = "BCM 25", + }); + + internal static readonly Lazy Pin26 = new Lazy(() => new GpioPin(BcmPin.Gpio26) { + Capabilities = PinCapability.GP, + Name = "BCM 26", + }); + + internal static readonly Lazy Pin27 = new Lazy(() => new GpioPin(BcmPin.Gpio27) { + Capabilities = PinCapability.GP, + Name = "BCM 27", + }); + + internal static readonly Lazy Pin28 = new Lazy(() => new GpioPin(BcmPin.Gpio28) { + Capabilities = PinCapability.GP | PinCapability.I2CSDA, + Name = "BCM 28 (SDA)", + }); + + internal static readonly Lazy Pin29 = new Lazy(() => new GpioPin(BcmPin.Gpio29) { + Capabilities = PinCapability.GP | PinCapability.I2CSCL, + Name = "BCM 29 (SCL)", + }); + + internal static readonly Lazy Pin30 = new Lazy(() => new GpioPin(BcmPin.Gpio30) { + Capabilities = PinCapability.GP, + Name = "BCM 30", + }); + + internal static readonly Lazy Pin31 = new Lazy(() => new GpioPin(BcmPin.Gpio31) { + Capabilities = PinCapability.GP, + Name = "BCM 31", + }); + } } \ No newline at end of file diff --git a/Unosquare.WiringPi/GpioPin.cs b/Unosquare.WiringPi/GpioPin.cs index e65ecf9..8fec72f 100644 --- a/Unosquare.WiringPi/GpioPin.cs +++ b/Unosquare.WiringPi/GpioPin.cs @@ -1,654 +1,583 @@ -namespace Unosquare.WiringPi -{ - using System; - using System.Threading.Tasks; - using Native; - using RaspberryIO.Abstractions; - using RaspberryIO.Abstractions.Native; - using Swan.Diagnostics; - using Definitions = RaspberryIO.Abstractions.Definitions; - +using System; +using System.Threading.Tasks; + +using Swan.Diagnostics; + +using Unosquare.RaspberryIO.Abstractions; +using Unosquare.RaspberryIO.Abstractions.Native; + +using Definitions = Unosquare.RaspberryIO.Abstractions.Definitions; + +namespace Unosquare.WiringPi { + /// + /// Represents a GPIO Pin, its location and its capabilities. + /// Full pin reference available here: + /// http://pinout.xyz/pinout/pin31_gpio6 and http://wiringpi.com/pins/. + /// + public sealed partial class GpioPin : IGpioPin { + #region Property Backing + + private static readonly Int32[] GpioToWiringPi; + + private static readonly Int32[] GpioToWiringPiR1 = { 8, 9, -1, -1, 7, -1, -1, 11, 10, 13, 12, 14, -1, -1, 15, 16, -1, 0, 1, -1, -1, 2, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1 }; + + private static readonly Int32[] GpioToWiringPiR2 = { 30, 31, 8, 9, 7, 21, 22, 11, 10, 13, 12, 14, 26, 23, 15, 16, 27, 0, 1, 24, 28, 29, 3, 4, 5, 6, 25, 2, 17, 18, 19, 20 }; + + private readonly Object _syncLock = new Object(); + private GpioPinDriveMode _pinMode; + private GpioPinResistorPullMode _resistorPullMode; + private Int32 _pwmRegister; + private PwmMode _pwmMode = PwmMode.Balanced; + private UInt32 _pwmRange = 1024; + private Int32 _pwmClockDivisor = 1; + private Int32 _softPwmValue = -1; + private Int32 _softToneFrequency = -1; + + #endregion + + #region Constructor + + static GpioPin() => GpioToWiringPi = SystemInfo.GetBoardRevision() == BoardRevision.Rev1 ? GpioToWiringPiR1 : GpioToWiringPiR2; + /// - /// Represents a GPIO Pin, its location and its capabilities. - /// Full pin reference available here: - /// http://pinout.xyz/pinout/pin31_gpio6 and http://wiringpi.com/pins/. + /// Initializes a new instance of the class. /// - public sealed partial class GpioPin : IGpioPin - { - #region Property Backing - - private static readonly int[] GpioToWiringPi; - - private static readonly int[] GpioToWiringPiR1 = - { - 8, 9, -1, -1, 7, -1, -1, 11, 10, 13, 12, 14, -1, -1, 15, 16, -1, 0, 1, -1, -1, 2, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, - }; - - private static readonly int[] GpioToWiringPiR2 = - { - 30, 31, 8, 9, 7, 21, 22, 11, 10, 13, 12, 14, 26, 23, 15, 16, 27, 0, 1, 24, 28, 29, 3, 4, 5, 6, 25, 2, 17, 18, 19, 20, - }; - - private readonly object _syncLock = new object(); - private GpioPinDriveMode _pinMode; - private GpioPinResistorPullMode _resistorPullMode; - private int _pwmRegister; - private PwmMode _pwmMode = PwmMode.Balanced; - private uint _pwmRange = 1024; - private int _pwmClockDivisor = 1; - private int _softPwmValue = -1; - private int _softToneFrequency = -1; - - #endregion - - #region Constructor - - static GpioPin() - { - GpioToWiringPi = SystemInfo.GetBoardRevision() == - BoardRevision.Rev1 ? GpioToWiringPiR1 : GpioToWiringPiR2; - } - - /// - /// Initializes a new instance of the class. - /// - /// The BCM pin number. - private GpioPin(BcmPin bcmPinNumber) - { - BcmPin = bcmPinNumber; - BcmPinNumber = (int)bcmPinNumber; - - WiringPiPinNumber = BcmToWiringPiPinNumber(bcmPinNumber); - PhysicalPinNumber = Definitions.BcmToPhysicalPinNumber(SystemInfo.GetBoardRevision(), bcmPinNumber); - Header = (BcmPinNumber >= 28 && BcmPinNumber <= 31) ? GpioHeader.P5 : GpioHeader.P1; - } - - #endregion - - #region Pin Properties - - /// - public BcmPin BcmPin { get; } - - /// - public int BcmPinNumber { get; } - - /// - public int PhysicalPinNumber { get; } - - /// - /// Gets the WiringPi Pin number. - /// - public WiringPiPin WiringPiPinNumber { get; } - - /// - public GpioHeader Header { get; } - - /// - /// Gets the friendly name of the pin. - /// - public string Name { get; private set; } - - /// - /// Gets the hardware mode capabilities of this pin. - /// - public PinCapability Capabilities { get; private set; } - - /// - public bool Value - { - get => Read(); - set => Write(value); - } - - #endregion - - #region Hardware-Specific Properties - - /// - /// Thrown when a pin does not support the given operation mode. - public GpioPinDriveMode PinMode - { - get => _pinMode; - - set - { - lock (_syncLock) - { - var mode = value; - if ((mode == GpioPinDriveMode.GpioClock && !HasCapability(PinCapability.GPCLK)) || - (mode == GpioPinDriveMode.PwmOutput && !HasCapability(PinCapability.PWM)) || - (mode == GpioPinDriveMode.Input && !HasCapability(PinCapability.GP)) || - (mode == GpioPinDriveMode.Output && !HasCapability(PinCapability.GP))) - { - throw new NotSupportedException( - $"Pin {BcmPinNumber} '{Name}' does not support mode '{mode}'. Pin capabilities are limited to: {Capabilities}"); - } - - WiringPi.PinMode(BcmPinNumber, (int)mode); - _pinMode = mode; - } - } - } - - /// - /// Gets the interrupt callback. Returns null if no interrupt - /// has been registered. - /// - public InterruptServiceRoutineCallback InterruptCallback { get; private set; } - - /// - /// Gets the interrupt edge detection mode. - /// - public EdgeDetection InterruptEdgeDetection { get; private set; } - - /// - /// Determines whether the specified capability has capability. - /// - /// The capability. - /// - /// true if the specified capability has capability; otherwise, false. - /// - public bool HasCapability(PinCapability capability) => - (Capabilities & capability) == capability; - - #endregion - - #region Hardware PWM Members - - /// - public GpioPinResistorPullMode InputPullMode - { - get => PinMode == GpioPinDriveMode.Input ? _resistorPullMode : GpioPinResistorPullMode.Off; - - set - { - lock (_syncLock) - { - if (PinMode != GpioPinDriveMode.Input) - { - _resistorPullMode = GpioPinResistorPullMode.Off; - throw new InvalidOperationException( - $"Unable to set the {nameof(InputPullMode)} for pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Setting the {nameof(InputPullMode)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); - } - - WiringPi.PullUpDnControl(BcmPinNumber, (int)value); - _resistorPullMode = value; - } - } - } - - /// - /// Gets or sets the PWM register. - /// - /// - /// The PWM register. - /// - public int PwmRegister - { - get => _pwmRegister; - - set - { - lock (_syncLock) - { - if (!HasCapability(PinCapability.PWM)) - { - _pwmRegister = 0; - - throw new NotSupportedException( - $"Pin {BcmPinNumber} '{Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {Capabilities}"); - } - - WiringPi.PwmWrite(BcmPinNumber, value); - _pwmRegister = value; - } - } - } - - /// - /// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional, - /// however the default mode in the Pi is “balanced”. - /// - /// - /// The PWM mode. - /// - /// When pin mode is not set a Pwn output. - public PwmMode PwmMode - { - get => PinMode == GpioPinDriveMode.PwmOutput ? _pwmMode : PwmMode.Balanced; - - set - { - lock (_syncLock) - { - if (!HasCapability(PinCapability.PWM)) - { - _pwmMode = PwmMode.Balanced; - - throw new NotSupportedException( - $"Pin {BcmPinNumber} '{Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {Capabilities}"); - } - - WiringPi.PwmSetMode((int)value); - _pwmMode = value; - } - } - } - - /// - /// This sets the range register in the PWM generator. The default is 1024. - /// - /// - /// The PWM range. - /// - /// When pin mode is not set to PWM output. - public uint PwmRange - { - get => PinMode == GpioPinDriveMode.PwmOutput ? _pwmRange : 0; - - set - { - lock (_syncLock) - { - if (!HasCapability(PinCapability.PWM)) - { - _pwmRange = 1024; - - throw new NotSupportedException( - $"Pin {BcmPinNumber} '{Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {Capabilities}"); - } - - WiringPi.PwmSetRange(value); - _pwmRange = value; - } - } - } - - /// - /// Gets or sets the PWM clock divisor. - /// - /// - /// The PWM clock divisor. - /// - /// When pin mode is not set to PWM output. - public int PwmClockDivisor - { - get => PinMode == GpioPinDriveMode.PwmOutput ? _pwmClockDivisor : 0; - - set - { - lock (_syncLock) - { - if (!HasCapability(PinCapability.PWM)) - { - _pwmClockDivisor = 1; - - throw new NotSupportedException( - $"Pin {BcmPinNumber} '{Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {Capabilities}"); - } - - WiringPi.PwmSetClock(value); - _pwmClockDivisor = value; - } - } - } - - #endregion - - #region Software Tone Members - - /// - /// Gets a value indicating whether this instance is in software based tone generator mode. - /// - /// - /// true if this instance is in soft tone mode; otherwise, false. - /// - public bool IsInSoftToneMode => _softToneFrequency >= 0; - - /// - /// Gets or sets the soft tone frequency. 0 to 5000 Hz is typical. - /// - /// - /// The soft tone frequency. - /// - /// When soft tones cannot be initialized on the pin. - public int SoftToneFrequency - { - get => _softToneFrequency; - - set - { - lock (_syncLock) - { - if (IsInSoftToneMode == false) - { - var setupResult = WiringPi.SoftToneCreate(BcmPinNumber); - if (setupResult != 0) - { - throw new InvalidOperationException( - $"Unable to initialize soft tone on pin {BcmPinNumber}. Error Code: {setupResult}"); - } - } - - WiringPi.SoftToneWrite(BcmPinNumber, value); - _softToneFrequency = value; - } - } - } - - #endregion - - #region Software PWM Members - - /// - /// Gets a value indicating whether this pin is in software based PWM mode. - /// - /// - /// true if this instance is in soft PWM mode; otherwise, false. - /// - public bool IsInSoftPwmMode => _softPwmValue >= 0; - - /// - /// Gets or sets the software PWM value on the pin. - /// - /// - /// The soft PWM value. - /// - /// StartSoftPwm. - public int SoftPwmValue - { - get => _softPwmValue; - - set - { - lock (_syncLock) - { - if (IsInSoftPwmMode && value >= 0) - { - WiringPi.SoftPwmWrite(BcmPinNumber, value); - _softPwmValue = value; - } - else - { - throw new InvalidOperationException($"Software PWM requires a call to {nameof(StartSoftPwm)}."); - } - } - } - } - - /// - /// Gets the software PWM range used upon starting the PWM. - /// - public int SoftPwmRange { get; private set; } = -1; - - /// - /// Starts the software based PWM on this pin. - /// - /// The value. - /// The range. - /// When the pin does not suppoert PWM. - /// StartSoftPwm - /// or. - public void StartSoftPwm(int value, int range) - { - lock (_syncLock) - { - if (!HasCapability(PinCapability.GP)) - throw new NotSupportedException($"Pin {BcmPinNumber} does not support software PWM"); - - if (IsInSoftPwmMode) - throw new InvalidOperationException($"{nameof(StartSoftPwm)} has already been called."); - - var startResult = WiringPi.SoftPwmCreate(BcmPinNumber, value, range); - - if (startResult == 0) - { - _softPwmValue = value; - SoftPwmRange = range; - } - else - { - throw new InvalidOperationException( - $"Could not start software based PWM on pin {BcmPinNumber}. Error code: {startResult}"); - } - } - } - - #endregion - - #region Output Mode (Write) Members - - /// - public void Write(GpioPinValue value) - { - lock (_syncLock) - { - if (PinMode != GpioPinDriveMode.Output) - { - throw new InvalidOperationException( - $"Unable to write to pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}"); - } - - WiringPi.DigitalWrite(BcmPinNumber, (int)value); - } - } - - /// - /// Writes the value asynchronously. - /// - /// The value. - /// The awaitable task. - public Task WriteAsync(GpioPinValue value) => Task.Run(() => { Write(value); }); - - /// - /// Writes the specified bit value. - /// This method performs a digital write. - /// - /// if set to true [value]. - public void Write(bool value) - => Write(value ? GpioPinValue.High : GpioPinValue.Low); - - /// - /// Writes the specified bit value. - /// This method performs a digital write. - /// - /// The value. - /// - /// The awaitable task. - /// - public Task WriteAsync(bool value) => Task.Run(() => { Write(value); }); - - /// - /// Writes the specified value. 0 for low, any other value for high - /// This method performs a digital write. - /// - /// The value. - public void Write(int value) => Write(value != 0 ? GpioPinValue.High : GpioPinValue.Low); - - /// - /// Writes the specified value. 0 for low, any other value for high - /// This method performs a digital write. - /// - /// The value. - /// The awaitable task. - public Task WriteAsync(int value) => Task.Run(() => { Write(value); }); - - /// - /// Writes the specified value as an analog level. - /// You will need to register additional analog modules to enable this function for devices such as the Gertboard. - /// - /// The value. - public void WriteLevel(int value) - { - lock (_syncLock) - { - if (PinMode != GpioPinDriveMode.Output) - { - throw new InvalidOperationException( - $"Unable to write to pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}"); - } - - WiringPi.AnalogWrite(BcmPinNumber, value); - } - } - - /// - /// Writes the specified value as an analog level. - /// You will need to register additional analog modules to enable this function for devices such as the Gertboard. - /// - /// The value. - /// The awaitable task. - public Task WriteLevelAsync(int value) => Task.Run(() => { WriteLevel(value); }); - - #endregion - - #region Input Mode (Read) Members - - /// - /// Wait for specific pin status. - /// - /// status to check. - /// timeout to reach status. - /// true/false. - public bool WaitForValue(GpioPinValue status, int timeOutMillisecond) - { - if (PinMode != GpioPinDriveMode.Input) - { - throw new InvalidOperationException( - $"Unable to read from pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); - } - - var hrt = new HighResolutionTimer(); - hrt.Start(); - do - { - if (ReadValue() == status) - return true; - } - while (hrt.ElapsedMilliseconds <= timeOutMillisecond); - - return false; - } - - /// - /// Reads the digital value on the pin as a boolean value. - /// - /// The state of the pin. - public bool Read() - { - lock (_syncLock) - { - if (PinMode != GpioPinDriveMode.Input && PinMode != GpioPinDriveMode.Output) - { - throw new InvalidOperationException( - $"Unable to read from pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); - } - - return WiringPi.DigitalRead(BcmPinNumber) != 0; - } - } - - /// - /// Reads the digital value on the pin as a boolean value. - /// - /// The state of the pin. - public Task ReadAsync() => Task.Run(Read); - - /// - /// Reads the digital value on the pin as a High or Low value. - /// - /// The state of the pin. - public GpioPinValue ReadValue() - => Read() ? GpioPinValue.High : GpioPinValue.Low; - - /// - /// Reads the digital value on the pin as a High or Low value. - /// - /// The state of the pin. - public Task ReadValueAsync() => Task.Run(ReadValue); - - /// - /// Reads the analog value on the pin. - /// This returns the value read on the supplied analog input pin. You will need to register - /// additional analog modules to enable this function for devices such as the Gertboard, - /// quick2Wire analog board, etc. - /// - /// The analog level. - /// When the pin mode is not configured as an input. - public int ReadLevel() - { - lock (_syncLock) - { - if (PinMode != GpioPinDriveMode.Input) - { - throw new InvalidOperationException( - $"Unable to read from pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); - } - - return WiringPi.AnalogRead(BcmPinNumber); - } - } - - /// - /// Reads the analog value on the pin. - /// This returns the value read on the supplied analog input pin. You will need to register - /// additional analog modules to enable this function for devices such as the Gertboard, - /// quick2Wire analog board, etc. - /// - /// The analog level. - public Task ReadLevelAsync() => Task.Run(ReadLevel); - - #endregion - - #region Interrupts - - /// - /// callback. - public void RegisterInterruptCallback(EdgeDetection edgeDetection, Action callback) - { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - - if (PinMode != GpioPinDriveMode.Input) - { - throw new InvalidOperationException( - $"Unable to {nameof(RegisterInterruptCallback)} for pin {BcmPinNumber} because operating mode is {PinMode}." - + $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); - } - - lock (_syncLock) - { - var isrCallback = new InterruptServiceRoutineCallback(callback); - var registerResult = WiringPi.WiringPiISR(BcmPinNumber, GetWiringPiEdgeDetection(edgeDetection), isrCallback); - if (registerResult == 0) - { - InterruptEdgeDetection = edgeDetection; - InterruptCallback = isrCallback; - } - else - { - HardwareException.Throw(nameof(GpioPin), nameof(RegisterInterruptCallback)); - } - } - } - - /// - public void RegisterInterruptCallback(EdgeDetection edgeDetection, Action callback) => - throw new NotSupportedException("WiringPi does only support a simple interrupt callback that has no parameters."); - - internal static WiringPiPin BcmToWiringPiPinNumber(BcmPin pin) => - (WiringPiPin)GpioToWiringPi[(int)pin]; - - private static int GetWiringPiEdgeDetection(EdgeDetection edgeDetection) => - GpioController.WiringPiEdgeDetectionMapping[edgeDetection]; - - #endregion - } + /// The BCM pin number. + private GpioPin(BcmPin bcmPinNumber) { + this.BcmPin = bcmPinNumber; + this.BcmPinNumber = (Int32)bcmPinNumber; + + this.WiringPiPinNumber = BcmToWiringPiPinNumber(bcmPinNumber); + this.PhysicalPinNumber = Definitions.BcmToPhysicalPinNumber(SystemInfo.GetBoardRevision(), bcmPinNumber); + this.Header = (this.BcmPinNumber >= 28 && this.BcmPinNumber <= 31) ? GpioHeader.P5 : GpioHeader.P1; + } + + #endregion + + #region Pin Properties + + /// + public BcmPin BcmPin { + get; + } + + /// + public Int32 BcmPinNumber { + get; + } + + /// + public Int32 PhysicalPinNumber { + get; + } + + /// + /// Gets the WiringPi Pin number. + /// + public WiringPiPin WiringPiPinNumber { + get; + } + + /// + public GpioHeader Header { + get; + } + + /// + /// Gets the friendly name of the pin. + /// + public String Name { + get; private set; + } + + /// + /// Gets the hardware mode capabilities of this pin. + /// + public PinCapability Capabilities { + get; private set; + } + + /// + public Boolean Value { + get => this.Read(); + set => this.Write(value); + } + + #endregion + + #region Hardware-Specific Properties + + /// + /// Thrown when a pin does not support the given operation mode. + public GpioPinDriveMode PinMode { + get => this._pinMode; + + set { + lock(this._syncLock) { + GpioPinDriveMode mode = value; + if(mode == GpioPinDriveMode.GpioClock && !this.HasCapability(PinCapability.GPCLK) || + mode == GpioPinDriveMode.PwmOutput && !this.HasCapability(PinCapability.PWM) || + mode == GpioPinDriveMode.Input && !this.HasCapability(PinCapability.GP) || + mode == GpioPinDriveMode.Output && !this.HasCapability(PinCapability.GP)) { + throw new NotSupportedException($"Pin {this.BcmPinNumber} '{this.Name}' does not support mode '{mode}'. Pin capabilities are limited to: {this.Capabilities}"); + } + + Native.WiringPi.PinMode(this.BcmPinNumber, (Int32)mode); + this._pinMode = mode; + } + } + } + + /// + /// Gets the interrupt callback. Returns null if no interrupt + /// has been registered. + /// + public Native.InterruptServiceRoutineCallback InterruptCallback { + get; private set; + } + + /// + /// Gets the interrupt edge detection mode. + /// + public EdgeDetection InterruptEdgeDetection { + get; private set; + } + + /// + /// Determines whether the specified capability has capability. + /// + /// The capability. + /// + /// true if the specified capability has capability; otherwise, false. + /// + public Boolean HasCapability(PinCapability capability) => (this.Capabilities & capability) == capability; + + #endregion + + #region Hardware PWM Members + + /// + public GpioPinResistorPullMode InputPullMode { + get => this.PinMode == GpioPinDriveMode.Input ? this._resistorPullMode : GpioPinResistorPullMode.Off; + + set { + lock(this._syncLock) { + if(this.PinMode != GpioPinDriveMode.Input) { + this._resistorPullMode = GpioPinResistorPullMode.Off; + throw new InvalidOperationException($"Unable to set the {nameof(this.InputPullMode)} for pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Setting the {nameof(this.InputPullMode)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}"); + } + + Native.WiringPi.PullUpDnControl(this.BcmPinNumber, (Int32)value); + this._resistorPullMode = value; + } + } + } + + /// + /// Gets or sets the PWM register. + /// + /// + /// The PWM register. + /// + public Int32 PwmRegister { + get => this._pwmRegister; + + set { + lock(this._syncLock) { + if(!this.HasCapability(PinCapability.PWM)) { + this._pwmRegister = 0; + + throw new NotSupportedException($"Pin {this.BcmPinNumber} '{this.Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {this.Capabilities}"); + } + + Native.WiringPi.PwmWrite(this.BcmPinNumber, value); + this._pwmRegister = value; + } + } + } + + /// + /// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional, + /// however the default mode in the Pi is “balanced”. + /// + /// + /// The PWM mode. + /// + /// When pin mode is not set a Pwn output. + public PwmMode PwmMode { + get => this.PinMode == GpioPinDriveMode.PwmOutput ? this._pwmMode : PwmMode.Balanced; + + set { + lock(this._syncLock) { + if(!this.HasCapability(PinCapability.PWM)) { + this._pwmMode = PwmMode.Balanced; + + throw new NotSupportedException($"Pin {this.BcmPinNumber} '{this.Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {this.Capabilities}"); + } + + Native.WiringPi.PwmSetMode((Int32)value); + this._pwmMode = value; + } + } + } + + /// + /// This sets the range register in the PWM generator. The default is 1024. + /// + /// + /// The PWM range. + /// + /// When pin mode is not set to PWM output. + public UInt32 PwmRange { + get => this.PinMode == GpioPinDriveMode.PwmOutput ? this._pwmRange : 0; + + set { + lock(this._syncLock) { + if(!this.HasCapability(PinCapability.PWM)) { + this._pwmRange = 1024; + + throw new NotSupportedException($"Pin {this.BcmPinNumber} '{this.Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {this.Capabilities}"); + } + + Native.WiringPi.PwmSetRange(value); + this._pwmRange = value; + } + } + } + + /// + /// Gets or sets the PWM clock divisor. + /// + /// + /// The PWM clock divisor. + /// + /// When pin mode is not set to PWM output. + public Int32 PwmClockDivisor { + get => this.PinMode == GpioPinDriveMode.PwmOutput ? this._pwmClockDivisor : 0; + + set { + lock(this._syncLock) { + if(!this.HasCapability(PinCapability.PWM)) { + this._pwmClockDivisor = 1; + + throw new NotSupportedException($"Pin {this.BcmPinNumber} '{this.Name}' does not support mode '{GpioPinDriveMode.PwmOutput}'. Pin capabilities are limited to: {this.Capabilities}"); + } + + Native.WiringPi.PwmSetClock(value); + this._pwmClockDivisor = value; + } + } + } + + #endregion + + #region Software Tone Members + + /// + /// Gets a value indicating whether this instance is in software based tone generator mode. + /// + /// + /// true if this instance is in soft tone mode; otherwise, false. + /// + public Boolean IsInSoftToneMode => this._softToneFrequency >= 0; + + /// + /// Gets or sets the soft tone frequency. 0 to 5000 Hz is typical. + /// + /// + /// The soft tone frequency. + /// + /// When soft tones cannot be initialized on the pin. + public Int32 SoftToneFrequency { + get => this._softToneFrequency; + + set { + lock(this._syncLock) { + if(this.IsInSoftToneMode == false) { + Int32 setupResult = Native.WiringPi.SoftToneCreate(this.BcmPinNumber); + if(setupResult != 0) { + throw new InvalidOperationException($"Unable to initialize soft tone on pin {this.BcmPinNumber}. Error Code: {setupResult}"); + } + } + + Native.WiringPi.SoftToneWrite(this.BcmPinNumber, value); + this._softToneFrequency = value; + } + } + } + + #endregion + + #region Software PWM Members + + /// + /// Gets a value indicating whether this pin is in software based PWM mode. + /// + /// + /// true if this instance is in soft PWM mode; otherwise, false. + /// + public Boolean IsInSoftPwmMode => this._softPwmValue >= 0; + + /// + /// Gets or sets the software PWM value on the pin. + /// + /// + /// The soft PWM value. + /// + /// StartSoftPwm. + public Int32 SoftPwmValue { + get => this._softPwmValue; + + set { + lock(this._syncLock) { + if(this.IsInSoftPwmMode && value >= 0) { + Native.WiringPi.SoftPwmWrite(this.BcmPinNumber, value); + this._softPwmValue = value; + } else { + throw new InvalidOperationException($"Software PWM requires a call to {nameof(StartSoftPwm)}."); + } + } + } + } + + /// + /// Gets the software PWM range used upon starting the PWM. + /// + public Int32 SoftPwmRange { get; private set; } = -1; + + /// + /// Starts the software based PWM on this pin. + /// + /// The value. + /// The range. + /// When the pin does not suppoert PWM. + /// StartSoftPwm + /// or. + public void StartSoftPwm(Int32 value, Int32 range) { + lock(this._syncLock) { + if(!this.HasCapability(PinCapability.GP)) { + throw new NotSupportedException($"Pin {this.BcmPinNumber} does not support software PWM"); + } + + if(this.IsInSoftPwmMode) { + throw new InvalidOperationException($"{nameof(StartSoftPwm)} has already been called."); + } + + Int32 startResult = Native.WiringPi.SoftPwmCreate(this.BcmPinNumber, value, range); + + if(startResult == 0) { + this._softPwmValue = value; + this.SoftPwmRange = range; + } else { + throw new InvalidOperationException($"Could not start software based PWM on pin {this.BcmPinNumber}. Error code: {startResult}"); + } + } + } + + #endregion + + #region Output Mode (Write) Members + + /// + public void Write(GpioPinValue value) { + lock(this._syncLock) { + if(this.PinMode != GpioPinDriveMode.Output) { + throw new InvalidOperationException($"Unable to write to pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Writes are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Output}"); + } + + Native.WiringPi.DigitalWrite(this.BcmPinNumber, (Int32)value); + } + } + + /// + /// Writes the value asynchronously. + /// + /// The value. + /// The awaitable task. + public Task WriteAsync(GpioPinValue value) => Task.Run(() => { this.Write(value); }); + + /// + /// Writes the specified bit value. + /// This method performs a digital write. + /// + /// if set to true [value]. + public void Write(Boolean value) => this.Write(value ? GpioPinValue.High : GpioPinValue.Low); + + /// + /// Writes the specified bit value. + /// This method performs a digital write. + /// + /// The value. + /// + /// The awaitable task. + /// + public Task WriteAsync(Boolean value) => Task.Run(() => { this.Write(value); }); + + /// + /// Writes the specified value. 0 for low, any other value for high + /// This method performs a digital write. + /// + /// The value. + public void Write(Int32 value) => this.Write(value != 0 ? GpioPinValue.High : GpioPinValue.Low); + + /// + /// Writes the specified value. 0 for low, any other value for high + /// This method performs a digital write. + /// + /// The value. + /// The awaitable task. + public Task WriteAsync(Int32 value) => Task.Run(() => { this.Write(value); }); + + /// + /// Writes the specified value as an analog level. + /// You will need to register additional analog modules to enable this function for devices such as the Gertboard. + /// + /// The value. + public void WriteLevel(Int32 value) { + lock(this._syncLock) { + if(this.PinMode != GpioPinDriveMode.Output) { + throw new InvalidOperationException($"Unable to write to pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Writes are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Output}"); + } + + Native.WiringPi.AnalogWrite(this.BcmPinNumber, value); + } + } + + /// + /// Writes the specified value as an analog level. + /// You will need to register additional analog modules to enable this function for devices such as the Gertboard. + /// + /// The value. + /// The awaitable task. + public Task WriteLevelAsync(Int32 value) => Task.Run(() => { this.WriteLevel(value); }); + + #endregion + + #region Input Mode (Read) Members + + /// + /// Wait for specific pin status. + /// + /// status to check. + /// timeout to reach status. + /// true/false. + public Boolean WaitForValue(GpioPinValue status, Int32 timeOutMillisecond) { + if(this.PinMode != GpioPinDriveMode.Input) { + throw new InvalidOperationException($"Unable to read from pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}"); + } + + HighResolutionTimer hrt = new HighResolutionTimer(); + hrt.Start(); + do { + if(this.ReadValue() == status) { + return true; + } + } + while(hrt.ElapsedMilliseconds <= timeOutMillisecond); + + return false; + } + + /// + /// Reads the digital value on the pin as a boolean value. + /// + /// The state of the pin. + public Boolean Read() { + lock(this._syncLock) { + if(this.PinMode != GpioPinDriveMode.Input && this.PinMode != GpioPinDriveMode.Output) { + throw new InvalidOperationException($"Unable to read from pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); + } + + return Native.WiringPi.DigitalRead(this.BcmPinNumber) != 0; + } + } + + /// + /// Reads the digital value on the pin as a boolean value. + /// + /// The state of the pin. + public Task ReadAsync() => Task.Run(this.Read); + + /// + /// Reads the digital value on the pin as a High or Low value. + /// + /// The state of the pin. + public GpioPinValue ReadValue() => this.Read() ? GpioPinValue.High : GpioPinValue.Low; + + /// + /// Reads the digital value on the pin as a High or Low value. + /// + /// The state of the pin. + public Task ReadValueAsync() => Task.Run(this.ReadValue); + + /// + /// Reads the analog value on the pin. + /// This returns the value read on the supplied analog input pin. You will need to register + /// additional analog modules to enable this function for devices such as the Gertboard, + /// quick2Wire analog board, etc. + /// + /// The analog level. + /// When the pin mode is not configured as an input. + public Int32 ReadLevel() { + lock(this._syncLock) { + if(this.PinMode != GpioPinDriveMode.Input) { + throw new InvalidOperationException($"Unable to read from pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}"); + } + + return Native.WiringPi.AnalogRead(this.BcmPinNumber); + } + } + + /// + /// Reads the analog value on the pin. + /// This returns the value read on the supplied analog input pin. You will need to register + /// additional analog modules to enable this function for devices such as the Gertboard, + /// quick2Wire analog board, etc. + /// + /// The analog level. + public Task ReadLevelAsync() => Task.Run(this.ReadLevel); + + #endregion + + #region Interrupts + + /// + /// callback. + public void RegisterInterruptCallback(EdgeDetection edgeDetection, Action callback) { + if(callback == null) { + throw new ArgumentNullException(nameof(callback)); + } + + if(this.PinMode != GpioPinDriveMode.Input) { + throw new InvalidOperationException($"Unable to {nameof(RegisterInterruptCallback)} for pin {this.BcmPinNumber} because operating mode is {this.PinMode}." + + $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}"); + } + + lock(this._syncLock) { + Native.InterruptServiceRoutineCallback isrCallback = new Native.InterruptServiceRoutineCallback(callback); + Int32 registerResult = Native.WiringPi.WiringPiISR(this.BcmPinNumber, GetWiringPiEdgeDetection(edgeDetection), isrCallback); + if(registerResult == 0) { + this.InterruptEdgeDetection = edgeDetection; + this.InterruptCallback = isrCallback; + } else { + HardwareException.Throw(nameof(GpioPin), nameof(RegisterInterruptCallback)); + } + } + } + + /// + public void RegisterInterruptCallback(EdgeDetection edgeDetection, Action callback) => throw new NotSupportedException("WiringPi does only support a simple interrupt callback that has no parameters."); + + internal static WiringPiPin BcmToWiringPiPinNumber(BcmPin pin) => (WiringPiPin)GpioToWiringPi[(Int32)pin]; + + private static Int32 GetWiringPiEdgeDetection(EdgeDetection edgeDetection) => GpioController.WiringPiEdgeDetectionMapping[edgeDetection]; + + #endregion + } } diff --git a/Unosquare.WiringPi/I2CBus.cs b/Unosquare.WiringPi/I2CBus.cs index 99dad15..925057f 100644 --- a/Unosquare.WiringPi/I2CBus.cs +++ b/Unosquare.WiringPi/I2CBus.cs @@ -1,72 +1,70 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; - +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// + /// A simple wrapper for the I2c bus on the Raspberry Pi. + /// + public class I2CBus : II2CBus { + // TODO: It would be nice to integrate i2c device detection. + private static readonly Object SyncRoot = new Object(); + private readonly Dictionary _devices = new Dictionary(); + /// + public ReadOnlyCollection Devices { + get { + lock(SyncRoot) { + return new ReadOnlyCollection(this._devices.Values.ToArray()); + } + } + } + + /// + public II2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId); + + /// + public II2CDevice GetDeviceById(Int32 deviceId) { + lock(SyncRoot) { + return this._devices[deviceId]; + } + } + + /// + /// When the device file descriptor is not found. + public II2CDevice AddDevice(Int32 deviceId) { + lock(SyncRoot) { + if(this._devices.ContainsKey(deviceId)) { + return this._devices[deviceId]; + } + + Int32 fileDescriptor = SetupFileDescriptor(deviceId); + if(fileDescriptor < 0) { + throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}."); + } + + I2CDevice device = new I2CDevice(deviceId, fileDescriptor); + this._devices[deviceId] = device; + return device; + } + } + /// - /// A simple wrapper for the I2c bus on the Raspberry Pi. + /// This initializes the I2C system with your given device identifier. + /// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. + /// wiringPiI2CSetup() will work out which revision Raspberry Pi you have and open the appropriate device in /dev. + /// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual. /// - public class I2CBus : II2CBus - { - // TODO: It would be nice to integrate i2c device detection. - private static readonly object SyncRoot = new object(); - private readonly Dictionary _devices = new Dictionary(); - - /// - public ReadOnlyCollection Devices - { - get - { - lock (SyncRoot) - return new ReadOnlyCollection(_devices.Values.ToArray()); - } - } - - /// - public II2CDevice this[int deviceId] => GetDeviceById(deviceId); - - /// - public II2CDevice GetDeviceById(int deviceId) - { - lock (SyncRoot) - return _devices[deviceId]; - } - - /// - /// When the device file descriptor is not found. - public II2CDevice AddDevice(int deviceId) - { - lock (SyncRoot) - { - if (_devices.ContainsKey(deviceId)) - return _devices[deviceId]; - - var fileDescriptor = SetupFileDescriptor(deviceId); - if (fileDescriptor < 0) - throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}."); - - var device = new I2CDevice(deviceId, fileDescriptor); - _devices[deviceId] = device; - return device; - } - } - - /// - /// This initializes the I2C system with your given device identifier. - /// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. - /// wiringPiI2CSetup() will work out which revision Raspberry Pi you have and open the appropriate device in /dev. - /// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual. - /// - /// The device identifier. - /// The Linux file handle. - private static int SetupFileDescriptor(int deviceId) - { - lock (SyncRoot) - return WiringPi.WiringPiI2CSetup(deviceId); - } - } + /// The device identifier. + /// The Linux file handle. + private static Int32 SetupFileDescriptor(Int32 deviceId) { + lock(SyncRoot) { + return Native.WiringPi.WiringPiI2CSetup(deviceId); + } + } + } } diff --git a/Unosquare.WiringPi/I2CDevice.cs b/Unosquare.WiringPi/I2CDevice.cs index ae4af68..2b33091 100644 --- a/Unosquare.WiringPi/I2CDevice.cs +++ b/Unosquare.WiringPi/I2CDevice.cs @@ -1,181 +1,182 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using RaspberryIO.Abstractions.Native; - using System; - using System.Threading.Tasks; - +using System; +using System.Threading.Tasks; + +using Unosquare.RaspberryIO.Abstractions; +using Unosquare.RaspberryIO.Abstractions.Native; + +namespace Unosquare.WiringPi { + /// + /// Represents a device on the I2C Bus. + /// + public class I2CDevice : II2CDevice { + private readonly Object _syncLock = new Object(); + /// - /// Represents a device on the I2C Bus. + /// Initializes a new instance of the class. /// - public class I2CDevice : II2CDevice - { - private readonly object _syncLock = new object(); - - /// - /// Initializes a new instance of the class. - /// - /// The device identifier. - /// The file descriptor. - internal I2CDevice(int deviceId, int fileDescriptor) - { - DeviceId = deviceId; - FileDescriptor = fileDescriptor; - } - - /// - public int DeviceId { get; } - - /// - public int FileDescriptor { get; } - - /// - public byte Read() - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CRead(FileDescriptor); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read)); - return (byte)result; - } - } - - /// - /// Reads a byte from the specified file descriptor. - /// - /// The byte from device. - public Task ReadAsync() => Task.Run(Read); - - /// - /// Reads a buffer of the specified length, one byte at a time. - /// - /// The length. - /// The byte array from device. - public byte[] Read(int length) - { - lock (_syncLock) - { - var buffer = new byte[length]; - for (var i = 0; i < length; i++) - { - var result = WiringPi.WiringPiI2CRead(FileDescriptor); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read)); - buffer[i] = (byte)result; - } - - return buffer; - } - } - - /// - /// Reads a buffer of the specified length, one byte at a time. - /// - /// The length. - /// The byte array from device. - public Task ReadAsync(int length) => Task.Run(() => Read(length)); - - /// - /// Writes a byte of data the specified file descriptor. - /// - /// The data. - public void Write(byte data) - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CWrite(FileDescriptor, data); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write)); - } - } - - /// - /// Writes a byte of data the specified file descriptor. - /// - /// The data. - /// The awaitable task. - public Task WriteAsync(byte data) => Task.Run(() => { Write(data); }); - - /// - /// Writes a set of bytes to the specified file descriptor. - /// - /// The data. - public void Write(byte[] data) - { - lock (_syncLock) - { - foreach (var b in data) - { - var result = WiringPi.WiringPiI2CWrite(FileDescriptor, b); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write)); - } - } - } - - /// - /// Writes a set of bytes to the specified file descriptor. - /// - /// The data. - /// The awaitable task. - public Task WriteAsync(byte[] data) => Task.Run(() => { Write(data); }); - - /// - /// These write an 8 or 16-bit data value into the device register indicated. - /// - /// The register. - /// The data. - public void WriteAddressByte(int address, byte data) - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CWriteReg8(FileDescriptor, address, data); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte)); - } - } - - /// - /// These write an 8 or 16-bit data value into the device register indicated. - /// - /// The register. - /// The data. - public void WriteAddressWord(int address, ushort data) - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CWriteReg16(FileDescriptor, address, data); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord)); - } - } - - /// - /// These read an 8 or 16-bit value from the device register indicated. - /// - /// The register. - /// The address byte from device. - public byte ReadAddressByte(int address) - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CReadReg8(FileDescriptor, address); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte)); - - return (byte)result; - } - } - - /// - /// These read an 8 or 16-bit value from the device register indicated. - /// - /// The register. - /// The address word from device. - public ushort ReadAddressWord(int address) - { - lock (_syncLock) - { - var result = WiringPi.WiringPiI2CReadReg16(FileDescriptor, address); - if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord)); - - return Convert.ToUInt16(result); - } - } - } + /// The device identifier. + /// The file descriptor. + internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) { + this.DeviceId = deviceId; + this.FileDescriptor = fileDescriptor; + } + + /// + public Int32 DeviceId { + get; + } + + /// + public Int32 FileDescriptor { + get; + } + + /// + public Byte Read() { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CRead(this.FileDescriptor); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(Read)); + } + + return (Byte)result; + } + } + + /// + /// Reads a byte from the specified file descriptor. + /// + /// The byte from device. + public Task ReadAsync() => Task.Run(this.Read); + + /// + /// Reads a buffer of the specified length, one byte at a time. + /// + /// The length. + /// The byte array from device. + public Byte[] Read(Int32 length) { + lock(this._syncLock) { + Byte[] buffer = new Byte[length]; + for(Int32 i = 0; i < length; i++) { + Int32 result = Native.WiringPi.WiringPiI2CRead(this.FileDescriptor); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(Read)); + } + + buffer[i] = (Byte)result; + } + + return buffer; + } + } + + /// + /// Reads a buffer of the specified length, one byte at a time. + /// + /// The length. + /// The byte array from device. + public Task ReadAsync(Int32 length) => Task.Run(() => this.Read(length)); + + /// + /// Writes a byte of data the specified file descriptor. + /// + /// The data. + public void Write(Byte data) { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CWrite(this.FileDescriptor, data); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(Write)); + } + } + } + + /// + /// Writes a byte of data the specified file descriptor. + /// + /// The data. + /// The awaitable task. + public Task WriteAsync(Byte data) => Task.Run(() => this.Write(data)); + + /// + /// Writes a set of bytes to the specified file descriptor. + /// + /// The data. + public void Write(Byte[] data) { + lock(this._syncLock) { + foreach(Byte b in data) { + Int32 result = Native.WiringPi.WiringPiI2CWrite(this.FileDescriptor, b); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(Write)); + } + } + } + } + + /// + /// Writes a set of bytes to the specified file descriptor. + /// + /// The data. + /// The awaitable task. + public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data)); + + /// + /// These write an 8 or 16-bit data value into the device register indicated. + /// + /// The register. + /// The data. + public void WriteAddressByte(Int32 address, Byte data) { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte)); + } + } + } + + /// + /// These write an 8 or 16-bit data value into the device register indicated. + /// + /// The register. + /// The data. + public void WriteAddressWord(Int32 address, UInt16 data) { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord)); + } + } + } + + /// + /// These read an 8 or 16-bit value from the device register indicated. + /// + /// The register. + /// The address byte from device. + public Byte ReadAddressByte(Int32 address) { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte)); + } + + return (Byte)result; + } + } + + /// + /// These read an 8 or 16-bit value from the device register indicated. + /// + /// The register. + /// The address word from device. + public UInt16 ReadAddressWord(Int32 address) { + lock(this._syncLock) { + Int32 result = Native.WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address); + if(result < 0) { + HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord)); + } + + return Convert.ToUInt16(result); + } + } + } } diff --git a/Unosquare.WiringPi/Native/Delegates.cs b/Unosquare.WiringPi/Native/Delegates.cs index 16f9934..66ce0a5 100644 --- a/Unosquare.WiringPi/Native/Delegates.cs +++ b/Unosquare.WiringPi/Native/Delegates.cs @@ -1,12 +1,11 @@ -namespace Unosquare.WiringPi.Native -{ - /// - /// A delegate defining a callback for an Interrupt Service Routine. - /// - public delegate void InterruptServiceRoutineCallback(); - - /// - /// Defines the body of a thread worker. - /// - public delegate void ThreadWorker(); +namespace Unosquare.WiringPi.Native { + /// + /// A delegate defining a callback for an Interrupt Service Routine. + /// + public delegate void InterruptServiceRoutineCallback(); + + /// + /// Defines the body of a thread worker. + /// + public delegate void ThreadWorker(); } diff --git a/Unosquare.WiringPi/Native/SysCall.cs b/Unosquare.WiringPi/Native/SysCall.cs index d33248d..37e7fef 100644 --- a/Unosquare.WiringPi/Native/SysCall.cs +++ b/Unosquare.WiringPi/Native/SysCall.cs @@ -1,19 +1,17 @@ -namespace Unosquare.WiringPi.Native -{ - using System; - using System.Runtime.InteropServices; - - internal static class SysCall - { - internal const string LibCLibrary = "libc"; - - [DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)] - public static extern int Chmod(string filename, uint mode); - - [DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)] - public static extern int StringToInteger(string numberString, IntPtr endPointer, int numberBase); - - [DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)] - public static extern int Write(int fd, byte[] buffer, int count); - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + internal static class SysCall { + internal const String LibCLibrary = "libc"; + + [DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)] + public static extern Int32 Chmod(String filename, UInt32 mode); + + [DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)] + public static extern Int32 StringToInteger(String numberString, IntPtr endPointer, Int32 numberBase); + + [DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)] + public static extern Int32 Write(Int32 fd, Byte[] buffer, Int32 count); + } } diff --git a/Unosquare.WiringPi/Native/WiringPi.I2C.cs b/Unosquare.WiringPi/Native/WiringPi.I2C.cs index 56a73d3..404d1ba 100644 --- a/Unosquare.WiringPi/Native/WiringPi.I2C.cs +++ b/Unosquare.WiringPi/Native/WiringPi.I2C.cs @@ -1,74 +1,73 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - - public partial class WiringPi - { - /// - /// Simple device read. Some devices present data when you read them without having to do any register transactions. - /// - /// The fd. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)] - public static extern int WiringPiI2CRead(int fd); - - /// - /// These read an 8-bit value from the device register indicated. - /// - /// The fd. - /// The reg. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)] - public static extern int WiringPiI2CReadReg8(int fd, int reg); - - /// - /// These read a 16-bit value from the device register indicated. - /// - /// The fd. - /// The reg. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)] - public static extern int WiringPiI2CReadReg16(int fd, int reg); - - /// - /// Simple device write. Some devices accept data this way without needing to access any internal registers. - /// - /// The fd. - /// The data. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)] - public static extern int WiringPiI2CWrite(int fd, int data); - - /// - /// These write an 8-bit data value into the device register indicated. - /// - /// The fd. - /// The reg. - /// The data. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)] - public static extern int WiringPiI2CWriteReg8(int fd, int reg, int data); - - /// - /// These write a 16-bit data value into the device register indicated. - /// - /// The fd. - /// The reg. - /// The data. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)] - public static extern int WiringPiI2CWriteReg16(int fd, int reg, int data); - - /// - /// This initializes the I2C system with your given device identifier. - /// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. wiringPiI2CSetup() - /// will work out which revision Raspberry Pi you have and open the appropriate device in /dev. - /// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual. - /// E.g. the popular MCP23017 GPIO expander is usually device Id 0x20, so this is the number you would pass into wiringPiI2CSetup(). - /// - /// The dev identifier. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)] - public static extern int WiringPiI2CSetup(int devId); - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + public partial class WiringPi { + /// + /// Simple device read. Some devices present data when you read them without having to do any register transactions. + /// + /// The fd. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)] + public static extern Int32 WiringPiI2CRead(Int32 fd); + + /// + /// These read an 8-bit value from the device register indicated. + /// + /// The fd. + /// The reg. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)] + public static extern Int32 WiringPiI2CReadReg8(Int32 fd, Int32 reg); + + /// + /// These read a 16-bit value from the device register indicated. + /// + /// The fd. + /// The reg. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)] + public static extern Int32 WiringPiI2CReadReg16(Int32 fd, Int32 reg); + + /// + /// Simple device write. Some devices accept data this way without needing to access any internal registers. + /// + /// The fd. + /// The data. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)] + public static extern Int32 WiringPiI2CWrite(Int32 fd, Int32 data); + + /// + /// These write an 8-bit data value into the device register indicated. + /// + /// The fd. + /// The reg. + /// The data. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)] + public static extern Int32 WiringPiI2CWriteReg8(Int32 fd, Int32 reg, Int32 data); + + /// + /// These write a 16-bit data value into the device register indicated. + /// + /// The fd. + /// The reg. + /// The data. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)] + public static extern Int32 WiringPiI2CWriteReg16(Int32 fd, Int32 reg, Int32 data); + + /// + /// This initializes the I2C system with your given device identifier. + /// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. wiringPiI2CSetup() + /// will work out which revision Raspberry Pi you have and open the appropriate device in /dev. + /// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual. + /// E.g. the popular MCP23017 GPIO expander is usually device Id 0x20, so this is the number you would pass into wiringPiI2CSetup(). + /// + /// The dev identifier. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)] + public static extern Int32 WiringPiI2CSetup(Int32 devId); + } } diff --git a/Unosquare.WiringPi/Native/WiringPi.SerialPort.cs b/Unosquare.WiringPi/Native/WiringPi.SerialPort.cs index 5ceb73d..35134d7 100644 --- a/Unosquare.WiringPi/Native/WiringPi.SerialPort.cs +++ b/Unosquare.WiringPi/Native/WiringPi.SerialPort.cs @@ -1,69 +1,68 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - - public partial class WiringPi - { - /// - /// This opens and initialises the serial device and sets the baud rate. It sets the port into “raw” mode (character at a time and no translations), - /// and sets the read timeout to 10 seconds. The return value is the file descriptor or -1 for any error, in which case errno will be set as appropriate. - /// The wiringSerial library is intended to provide simplified control – suitable for most applications, however if you need advanced control - /// – e.g. parity control, modem control lines (via a USB adapter, there are none on the Pi’s on-board UART!) and so on, - /// then you need to do some of this the old fashioned way. - /// - /// The device. - /// The baud. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)] - public static extern int SerialOpen(string device, int baud); - - /// - /// Closes the device identified by the file descriptor given. - /// - /// The fd. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)] - public static extern int SerialClose(int fd); - - /// - /// Sends the single byte to the serial device identified by the given file descriptor. - /// - /// The fd. - /// The c. - [DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)] - public static extern void SerialPutchar(int fd, byte c); - - /// - /// Sends the nul-terminated string to the serial device identified by the given file descriptor. - /// - /// The fd. - /// The s. - [DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)] - public static extern void SerialPuts(int fd, string s); - - /// - /// Returns the number of characters available for reading, or -1 for any error condition, - /// in which case errno will be set appropriately. - /// - /// The fd. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)] - public static extern int SerialDataAvail(int fd); - - /// - /// Returns the next character available on the serial device. - /// This call will block for up to 10 seconds if no data is available (when it will return -1). - /// - /// The fd. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)] - public static extern int SerialGetchar(int fd); - - /// - /// This discards all data received, or waiting to be send down the given device. - /// - /// The fd. - [DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)] - public static extern void SerialFlush(int fd); - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + public partial class WiringPi { + /// + /// This opens and initialises the serial device and sets the baud rate. It sets the port into “raw” mode (character at a time and no translations), + /// and sets the read timeout to 10 seconds. The return value is the file descriptor or -1 for any error, in which case errno will be set as appropriate. + /// The wiringSerial library is intended to provide simplified control – suitable for most applications, however if you need advanced control + /// – e.g. parity control, modem control lines (via a USB adapter, there are none on the Pi’s on-board UART!) and so on, + /// then you need to do some of this the old fashioned way. + /// + /// The device. + /// The baud. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)] + public static extern Int32 SerialOpen(String device, Int32 baud); + + /// + /// Closes the device identified by the file descriptor given. + /// + /// The fd. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)] + public static extern Int32 SerialClose(Int32 fd); + + /// + /// Sends the single byte to the serial device identified by the given file descriptor. + /// + /// The fd. + /// The c. + [DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)] + public static extern void SerialPutchar(Int32 fd, Byte c); + + /// + /// Sends the nul-terminated string to the serial device identified by the given file descriptor. + /// + /// The fd. + /// The s. + [DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)] + public static extern void SerialPuts(Int32 fd, String s); + + /// + /// Returns the number of characters available for reading, or -1 for any error condition, + /// in which case errno will be set appropriately. + /// + /// The fd. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)] + public static extern Int32 SerialDataAvail(Int32 fd); + + /// + /// Returns the next character available on the serial device. + /// This call will block for up to 10 seconds if no data is available (when it will return -1). + /// + /// The fd. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)] + public static extern Int32 SerialGetchar(Int32 fd); + + /// + /// This discards all data received, or waiting to be send down the given device. + /// + /// The fd. + [DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)] + public static extern void SerialFlush(Int32 fd); + } } \ No newline at end of file diff --git a/Unosquare.WiringPi/Native/WiringPi.Shift.cs b/Unosquare.WiringPi/Native/WiringPi.Shift.cs index 80cc913..d1912f0 100644 --- a/Unosquare.WiringPi/Native/WiringPi.Shift.cs +++ b/Unosquare.WiringPi/Native/WiringPi.Shift.cs @@ -1,36 +1,35 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - - public partial class WiringPi - { - #region WiringPi - Shift Library - - /// - /// This shifts an 8-bit data value in with the data appearing on the dPin and the clock being sent out on the cPin. - /// Order is either LSBFIRST or MSBFIRST. The data is sampled after the cPin goes high. - /// (So cPin high, sample data, cPin low, repeat for 8 bits) The 8-bit value is returned by the function. - /// - /// The d pin. - /// The c pin. - /// The order. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)] - public static extern byte ShiftIn(byte dPin, byte cPin, byte order); - - /// - /// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin. - /// order is as above. Data is clocked out on the rising or falling edge – ie. dPin is set, then cPin is taken high then low - /// – repeated for the 8 bits. - /// - /// The d pin. - /// The c pin. - /// The order. - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)] - public static extern void ShiftOut(byte dPin, byte cPin, byte order, byte val); - - #endregion - - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + public partial class WiringPi { + #region WiringPi - Shift Library + + /// + /// This shifts an 8-bit data value in with the data appearing on the dPin and the clock being sent out on the cPin. + /// Order is either LSBFIRST or MSBFIRST. The data is sampled after the cPin goes high. + /// (So cPin high, sample data, cPin low, repeat for 8 bits) The 8-bit value is returned by the function. + /// + /// The d pin. + /// The c pin. + /// The order. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)] + public static extern Byte ShiftIn(Byte dPin, Byte cPin, Byte order); + + /// + /// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin. + /// order is as above. Data is clocked out on the rising or falling edge – ie. dPin is set, then cPin is taken high then low + /// – repeated for the 8 bits. + /// + /// The d pin. + /// The c pin. + /// The order. + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)] + public static extern void ShiftOut(Byte dPin, Byte cPin, Byte order, Byte val); + + #endregion + + } } diff --git a/Unosquare.WiringPi/Native/WiringPi.SoftPwm.cs b/Unosquare.WiringPi/Native/WiringPi.SoftPwm.cs index b45bc26..a207ea8 100644 --- a/Unosquare.WiringPi/Native/WiringPi.SoftPwm.cs +++ b/Unosquare.WiringPi/Native/WiringPi.SoftPwm.cs @@ -1,64 +1,63 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - - public partial class WiringPi - { - #region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h) - - /// - /// This creates a software controlled PWM pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() - /// function you used. Use 100 for the pwmRange, then the value can be anything from 0 (off) to 100 (fully on) for the given pin. - /// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong. - /// - /// The pin. - /// The initial value. - /// The PWM range. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)] - public static extern int SoftPwmCreate(int pin, int initialValue, int pwmRange); - - /// - /// This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously - /// been initialized via softPwmCreate will be silently ignored. - /// - /// The pin. - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)] - public static extern void SoftPwmWrite(int pin, int value); - - /// - /// This function is undocumented. - /// - /// The pin. - [DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)] - public static extern void SoftPwmStop(int pin); - - /// - /// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used. - /// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong. - /// - /// The pin. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)] - public static extern int SoftToneCreate(int pin); - - /// - /// This function is undocumented. - /// - /// The pin. - [DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)] - public static extern void SoftToneStop(int pin); - - /// - /// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0. - /// - /// The pin. - /// The freq. - [DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)] - public static extern void SoftToneWrite(int pin, int freq); - - #endregion - - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + public partial class WiringPi { + #region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h) + + /// + /// This creates a software controlled PWM pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() + /// function you used. Use 100 for the pwmRange, then the value can be anything from 0 (off) to 100 (fully on) for the given pin. + /// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong. + /// + /// The pin. + /// The initial value. + /// The PWM range. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)] + public static extern Int32 SoftPwmCreate(Int32 pin, Int32 initialValue, Int32 pwmRange); + + /// + /// This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously + /// been initialized via softPwmCreate will be silently ignored. + /// + /// The pin. + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)] + public static extern void SoftPwmWrite(Int32 pin, Int32 value); + + /// + /// This function is undocumented. + /// + /// The pin. + [DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)] + public static extern void SoftPwmStop(Int32 pin); + + /// + /// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used. + /// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong. + /// + /// The pin. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)] + public static extern Int32 SoftToneCreate(Int32 pin); + + /// + /// This function is undocumented. + /// + /// The pin. + [DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)] + public static extern void SoftToneStop(Int32 pin); + + /// + /// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0. + /// + /// The pin. + /// The freq. + [DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)] + public static extern void SoftToneWrite(Int32 pin, Int32 freq); + + #endregion + + } } diff --git a/Unosquare.WiringPi/Native/WiringPi.Spi.cs b/Unosquare.WiringPi/Native/WiringPi.Spi.cs index 6e1cab1..8e7e479 100644 --- a/Unosquare.WiringPi/Native/WiringPi.Spi.cs +++ b/Unosquare.WiringPi/Native/WiringPi.Spi.cs @@ -1,53 +1,52 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - - public partial class WiringPi - { - #region WiringPi - SPI Library Calls - - /// - /// This function is undocumented. - /// - /// The channel. - /// Unknown. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)] - public static extern int WiringPiSPIGetFd(int channel); - - /// - /// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus. - /// That’s all there is in the helper library. It is possible to do simple read and writes over the SPI bus using the standard read() and write() system calls though – - /// write() may be better to use for sending data to chains of shift registers, or those LED strings where you send RGB triplets of data. - /// Devices such as A/D and D/A converters usually need to perform a concurrent write/read transaction to work. - /// - /// The channel. - /// The data. - /// The length. - /// The result. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)] - public static extern int WiringPiSPIDataRW(int channel, byte[] data, int len); - - /// - /// This function is undocumented. - /// - /// The channel. - /// The speed. - /// The mode. - /// Unkown. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)] - public static extern int WiringPiSPISetupMode(int channel, int speed, int mode); - - /// - /// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer - /// in the range 500,000 through 32,000,000 and represents the SPI clock speed in Hz. - /// The returned value is the Linux file-descriptor for the device, or -1 on error. If an error has happened, you may use the standard errno global variable to see why. - /// - /// The channel. - /// The speed. - /// The Linux file descriptor for the device or -1 for error. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)] - public static extern int WiringPiSPISetup(int channel, int speed); - - #endregion - } +using System; +using System.Runtime.InteropServices; + +namespace Unosquare.WiringPi.Native { + public partial class WiringPi { + #region WiringPi - SPI Library Calls + + /// + /// This function is undocumented. + /// + /// The channel. + /// Unknown. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)] + public static extern Int32 WiringPiSPIGetFd(Int32 channel); + + /// + /// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus. + /// That’s all there is in the helper library. It is possible to do simple read and writes over the SPI bus using the standard read() and write() system calls though – + /// write() may be better to use for sending data to chains of shift registers, or those LED strings where you send RGB triplets of data. + /// Devices such as A/D and D/A converters usually need to perform a concurrent write/read transaction to work. + /// + /// The channel. + /// The data. + /// The length. + /// The result. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)] + public static extern Int32 WiringPiSPIDataRW(Int32 channel, Byte[] data, Int32 len); + + /// + /// This function is undocumented. + /// + /// The channel. + /// The speed. + /// The mode. + /// Unkown. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)] + public static extern Int32 WiringPiSPISetupMode(Int32 channel, Int32 speed, Int32 mode); + + /// + /// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer + /// in the range 500,000 through 32,000,000 and represents the SPI clock speed in Hz. + /// The returned value is the Linux file-descriptor for the device, or -1 on error. If an error has happened, you may use the standard errno global variable to see why. + /// + /// The channel. + /// The speed. + /// The Linux file descriptor for the device or -1 for error. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)] + public static extern Int32 WiringPiSPISetup(Int32 channel, Int32 speed); + + #endregion + } } diff --git a/Unosquare.WiringPi/Native/WiringPi.cs b/Unosquare.WiringPi/Native/WiringPi.cs index 866f924..e2f06f7 100644 --- a/Unosquare.WiringPi/Native/WiringPi.cs +++ b/Unosquare.WiringPi/Native/WiringPi.cs @@ -1,376 +1,375 @@ -namespace Unosquare.WiringPi.Native -{ - using System.Runtime.InteropServices; - +using System.Runtime.InteropServices; +using System; + +namespace Unosquare.WiringPi.Native { + /// + /// Provides native C WiringPi Library function call wrappers + /// All credit for the native library goes to the author of http://wiringpi.com/ + /// The wrappers were written based on https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h. + /// + public partial class WiringPi { + internal const String WiringPiLibrary = "libwiringPi.so.2.50"; + + #region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h) + /// - /// Provides native C WiringPi Library function call wrappers - /// All credit for the native library goes to the author of http://wiringpi.com/ - /// The wrappers were written based on https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h. + /// This initialises wiringPi and assumes that the calling program is going to be using the wiringPi pin numbering scheme. + /// This is a simplified numbering scheme which provides a mapping from virtual pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers. + /// See the pins page for a table which maps the wiringPi pin number to the Broadcom GPIO pin number to the physical location on the edge connector. + /// This function needs to be called with root privileges. /// - public partial class WiringPi - { - internal const string WiringPiLibrary = "libwiringPi.so.2.50"; - - #region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h) - - /// - /// This initialises wiringPi and assumes that the calling program is going to be using the wiringPi pin numbering scheme. - /// This is a simplified numbering scheme which provides a mapping from virtual pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers. - /// See the pins page for a table which maps the wiringPi pin number to the Broadcom GPIO pin number to the physical location on the edge connector. - /// This function needs to be called with root privileges. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)] - public static extern int WiringPiSetup(); - - /// - /// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly. - /// This can be called as a non-root user provided the GPIO pins have been exported before-hand using the gpio program. - /// Pin numbering in this mode is the native Broadcom GPIO numbers – the same as wiringPiSetupGpio() above, - /// so be aware of the differences between Rev 1 and Rev 2 boards. - /// - /// Note: In this mode you can only use the pins which have been exported via the /sys/class/gpio interface before you run your program. - /// You can do this in a separate shell-script, or by using the system() function from inside your program to call the gpio program. - /// Also note that some functions have no effect when using this mode as they’re not currently possible to action unless called with root privileges. - /// (although you can use system() to call gpio to set/change modes if needed). - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)] - public static extern int WiringPiSetupSys(); - - /// - /// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO - /// pin numbers directly with no re-mapping. - /// As above, this function needs to be called with root privileges, and note that some pins are different - /// from revision 1 to revision 2 boards. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)] - public static extern int WiringPiSetupGpio(); - - /// - /// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only. - /// This function needs to be called with root privileges. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)] - public static extern int WiringPiSetupPhys(); - - /// - /// This function is undocumented. - /// - /// The pin. - /// The mode. - [DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)] - public static extern void PinModeAlt(int pin, int mode); - - /// - /// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK. - /// Note that only wiringPi pin 1 (BCM_GPIO 18) supports PWM output and only wiringPi pin 7 (BCM_GPIO 4) - /// supports CLOCK output modes. - /// - /// This function has no effect when in Sys mode. If you need to change the pin mode, then you can - /// do it with the gpio program in a script before you start your program. - /// - /// The pin. - /// The mode. - [DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)] - public static extern void PinMode(int pin, int mode); - - /// - /// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input. - /// Unlike the Arduino, the BCM2835 has both pull-up and down internal resistors. The parameter pud should be; PUD_OFF, - /// (no pull up/down), PUD_DOWN (pull to ground) or PUD_UP (pull to 3.3v) The internal pull up/down resistors - /// have a value of approximately 50KΩ on the Raspberry Pi. - /// - /// This function has no effect on the Raspberry Pi’s GPIO pins when in Sys mode. - /// If you need to activate a pull-up/pull-down, then you can do it with the gpio program in a script before you start your program. - /// - /// The pin. - /// The pud. - [DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)] - public static extern void PullUpDnControl(int pin, int pud); - - /// - /// This function returns the value read at the given pin. It will be HIGH or LOW (1 or 0) depending on the logic level at the pin. - /// - /// The pin. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)] - public static extern int DigitalRead(int pin); - - /// - /// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output. - /// WiringPi treats any non-zero number as HIGH, however 0 is the only representation of LOW. - /// - /// The pin. - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)] - public static extern void DigitalWrite(int pin, int value); - - /// - /// Writes the value to the PWM register for the given pin. The Raspberry Pi has one - /// on-board PWM pin, pin 1 (BMC_GPIO 18, Phys 12) and the range is 0-1024. - /// Other PWM devices may have other PWM ranges. - /// This function is not able to control the Pi’s on-board PWM when in Sys mode. - /// - /// The pin. - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)] - public static extern void PwmWrite(int pin, int value); - - /// - /// This returns the value read on the supplied analog input pin. You will need to - /// register additional analog modules to enable this function for devices such as the Gertboard, quick2Wire analog board, etc. - /// - /// The pin. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)] - public static extern int AnalogRead(int pin); - - /// - /// This writes the given value to the supplied analog pin. You will need to register additional - /// analog modules to enable this function for devices such as the Gertboard. - /// - /// The pin. - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)] - public static extern void AnalogWrite(int pin, int value); - - /// - /// This returns the board revision of the Raspberry Pi. It will be either 1 or 2. Some of the BCM_GPIO pins changed number and - /// function when moving from board revision 1 to 2, so if you are using BCM_GPIO pin numbers, then you need to be aware of the differences. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)] - public static extern int PiBoardRev(); - - /// - /// This function is undocumented. - /// - /// The model. - /// The memory. - /// The maker. - /// The over volted. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)] - public static extern int PiBoardId(ref int model, ref int mem, ref int maker, ref int overVolted); - - /// - /// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account. - /// - /// The w pi pin. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)] - public static extern int WpiPinToGpio(int wPiPin); - - /// - /// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector. - /// - /// The physical pin. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)] - public static extern int PhysPinToGpio(int physPin); - - /// - /// This sets the “strength” of the pad drivers for a particular group of pins. - /// There are 3 groups of pins and the drive strength is from 0 to 7. Do not use this unless you know what you are doing. - /// - /// The group. - /// The value. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)] - public static extern int SetPadDrive(int group, int value); - - /// - /// Undocumented function. - /// - /// The pin. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)] - public static extern int GetAlt(int pin); - - /// - /// Undocumented function. - /// - /// The pin. - /// The freq. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)] - public static extern int PwmToneWrite(int pin, int freq); - - /// - /// This writes the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware. - /// - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)] - public static extern void DigitalWriteByte(int value); - - /// - /// This writes the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware. - /// - /// The value. - [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)] - public static extern void DigitalWriteByte2(int value); - - /// - /// Undocumented function - /// This reads the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to get all 8 bits at once to a particular value. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)] - public static extern uint DigitalReadByte(); - - /// - /// Undocumented function - /// This reads the 8-bit byte supplied to the first 8 GPIO pins. - /// It’s the fastest way to get all 8 bits at once to a particular value. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)] - public static extern uint DigitalReadByte2(); - - /// - /// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional, - /// however the default mode in the Pi is “balanced”. You can switch modes by supplying the parameter: PWM_MODE_BAL or PWM_MODE_MS. - /// - /// The mode. - [DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)] - public static extern void PwmSetMode(int mode); - - /// - /// This sets the range register in the PWM generator. The default is 1024. - /// - /// The range. - [DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)] - public static extern void PwmSetRange(uint range); - - /// - /// This sets the divisor for the PWM clock. - /// Note: The PWM control functions can not be used when in Sys mode. - /// To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual. - /// - /// The divisor. - [DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)] - public static extern void PwmSetClock(int divisor); - - /// - /// Undocumented function. - /// - /// The pin. - /// The freq. - [DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)] - public static extern void GpioClockSet(int pin, int freq); - - /// - /// This function registers a function to received interrupts on the specified pin. - /// The edgeType parameter is either INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH or INT_EDGE_SETUP. - /// If it is INT_EDGE_SETUP then no initialisation of the pin will happen – it’s assumed that you have already setup the pin elsewhere - /// (e.g. with the gpio program), but if you specify one of the other types, then the pin will be exported and initialised as specified. - /// This is accomplished via a suitable call to the gpio utility program, so it need to be available. - /// The pin number is supplied in the current mode – native wiringPi, BCM_GPIO, physical or Sys modes. - /// This function will work in any mode, and does not need root privileges to work. - /// The function will be called when the interrupt triggers. When it is triggered, it’s cleared in the dispatcher before calling your function, - /// so if a subsequent interrupt fires before you finish your handler, then it won’t be missed. (However it can only track one more interrupt, - /// if more than one interrupt fires while one is being handled then they will be ignored) - /// This function is run at a high priority (if the program is run using sudo, or as root) and executes concurrently with the main program. - /// It has full access to all the global variables, open file handles and so on. - /// - /// The pin. - /// The mode. - /// The method. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)] - public static extern int WiringPiISR(int pin, int mode, InterruptServiceRoutineCallback method); - - /// - /// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration. - /// This function is then run concurrently with your main program. An example may be to have this function wait for an interrupt while - /// your program carries on doing other tasks. The thread can indicate an event, or action by using global variables to - /// communicate back to the main program, or other threads. - /// - /// The method. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)] - public static extern int PiThreadCreate(ThreadWorker method); - - /// - /// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key. - /// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key. - /// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread - /// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data – - /// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example. - /// - /// The key. - [DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)] - public static extern void PiLock(int key); - - /// - /// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key. - /// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key. - /// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread - /// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data – - /// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example. - /// - /// The key. - [DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)] - public static extern void PiUnlock(int key); - - /// - /// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority - /// and enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum). - /// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs are running. - /// The priority parameter works relative to others – so you can make one program priority 1 and another priority 2 - /// and it will have the same effect as setting one to 10 and the other to 90 (as long as no other - /// programs are running with elevated priorities) - /// The return value is 0 for success and -1 for error. If an error is returned, the program should then consult the errno global variable, as per the usual conventions. - /// Note: Only programs running as root can change their priority. If called from a non-root program then nothing happens. - /// - /// The priority. - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)] - public static extern int PiHiPri(int priority); - - /// - /// This causes program execution to pause for at least howLong milliseconds. - /// Due to the multi-tasking nature of Linux it could be longer. - /// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days. - /// - /// The how long. - [DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)] - public static extern void Delay(uint howLong); - - /// - /// This causes program execution to pause for at least howLong microseconds. - /// Due to the multi-tasking nature of Linux it could be longer. - /// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes. - /// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time, - /// Delays over 100 microseconds are done using the system nanosleep() function – You may need to consider the implications - /// of very short delays on the overall performance of the system, especially if using threads. - /// - /// The how long. - [DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)] - public static extern void DelayMicroseconds(uint howLong); - - /// - /// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions. - /// It returns an unsigned 32-bit number which wraps after 49 days. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)] - public static extern uint Millis(); - - /// - /// This returns a number representing the number of microseconds since your program called one of - /// the wiringPiSetup functions. It returns an unsigned 32-bit number which wraps after approximately 71 minutes. - /// - /// The result code. - [DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)] - public static extern uint Micros(); - - #endregion - } + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)] + public static extern Int32 WiringPiSetup(); + + /// + /// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly. + /// This can be called as a non-root user provided the GPIO pins have been exported before-hand using the gpio program. + /// Pin numbering in this mode is the native Broadcom GPIO numbers – the same as wiringPiSetupGpio() above, + /// so be aware of the differences between Rev 1 and Rev 2 boards. + /// + /// Note: In this mode you can only use the pins which have been exported via the /sys/class/gpio interface before you run your program. + /// You can do this in a separate shell-script, or by using the system() function from inside your program to call the gpio program. + /// Also note that some functions have no effect when using this mode as they’re not currently possible to action unless called with root privileges. + /// (although you can use system() to call gpio to set/change modes if needed). + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)] + public static extern Int32 WiringPiSetupSys(); + + /// + /// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO + /// pin numbers directly with no re-mapping. + /// As above, this function needs to be called with root privileges, and note that some pins are different + /// from revision 1 to revision 2 boards. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)] + public static extern Int32 WiringPiSetupGpio(); + + /// + /// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only. + /// This function needs to be called with root privileges. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)] + public static extern Int32 WiringPiSetupPhys(); + + /// + /// This function is undocumented. + /// + /// The pin. + /// The mode. + [DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)] + public static extern void PinModeAlt(Int32 pin, Int32 mode); + + /// + /// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK. + /// Note that only wiringPi pin 1 (BCM_GPIO 18) supports PWM output and only wiringPi pin 7 (BCM_GPIO 4) + /// supports CLOCK output modes. + /// + /// This function has no effect when in Sys mode. If you need to change the pin mode, then you can + /// do it with the gpio program in a script before you start your program. + /// + /// The pin. + /// The mode. + [DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)] + public static extern void PinMode(Int32 pin, Int32 mode); + + /// + /// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input. + /// Unlike the Arduino, the BCM2835 has both pull-up and down internal resistors. The parameter pud should be; PUD_OFF, + /// (no pull up/down), PUD_DOWN (pull to ground) or PUD_UP (pull to 3.3v) The internal pull up/down resistors + /// have a value of approximately 50KΩ on the Raspberry Pi. + /// + /// This function has no effect on the Raspberry Pi’s GPIO pins when in Sys mode. + /// If you need to activate a pull-up/pull-down, then you can do it with the gpio program in a script before you start your program. + /// + /// The pin. + /// The pud. + [DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)] + public static extern void PullUpDnControl(Int32 pin, Int32 pud); + + /// + /// This function returns the value read at the given pin. It will be HIGH or LOW (1 or 0) depending on the logic level at the pin. + /// + /// The pin. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)] + public static extern Int32 DigitalRead(Int32 pin); + + /// + /// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output. + /// WiringPi treats any non-zero number as HIGH, however 0 is the only representation of LOW. + /// + /// The pin. + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)] + public static extern void DigitalWrite(Int32 pin, Int32 value); + + /// + /// Writes the value to the PWM register for the given pin. The Raspberry Pi has one + /// on-board PWM pin, pin 1 (BMC_GPIO 18, Phys 12) and the range is 0-1024. + /// Other PWM devices may have other PWM ranges. + /// This function is not able to control the Pi’s on-board PWM when in Sys mode. + /// + /// The pin. + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)] + public static extern void PwmWrite(Int32 pin, Int32 value); + + /// + /// This returns the value read on the supplied analog input pin. You will need to + /// register additional analog modules to enable this function for devices such as the Gertboard, quick2Wire analog board, etc. + /// + /// The pin. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)] + public static extern Int32 AnalogRead(Int32 pin); + + /// + /// This writes the given value to the supplied analog pin. You will need to register additional + /// analog modules to enable this function for devices such as the Gertboard. + /// + /// The pin. + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)] + public static extern void AnalogWrite(Int32 pin, Int32 value); + + /// + /// This returns the board revision of the Raspberry Pi. It will be either 1 or 2. Some of the BCM_GPIO pins changed number and + /// function when moving from board revision 1 to 2, so if you are using BCM_GPIO pin numbers, then you need to be aware of the differences. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)] + public static extern Int32 PiBoardRev(); + + /// + /// This function is undocumented. + /// + /// The model. + /// The memory. + /// The maker. + /// The over volted. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)] + public static extern Int32 PiBoardId(ref Int32 model, ref Int32 mem, ref Int32 maker, ref Int32 overVolted); + + /// + /// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account. + /// + /// The w pi pin. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)] + public static extern Int32 WpiPinToGpio(Int32 wPiPin); + + /// + /// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector. + /// + /// The physical pin. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)] + public static extern Int32 PhysPinToGpio(Int32 physPin); + + /// + /// This sets the “strength” of the pad drivers for a particular group of pins. + /// There are 3 groups of pins and the drive strength is from 0 to 7. Do not use this unless you know what you are doing. + /// + /// The group. + /// The value. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)] + public static extern Int32 SetPadDrive(Int32 group, Int32 value); + + /// + /// Undocumented function. + /// + /// The pin. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)] + public static extern Int32 GetAlt(Int32 pin); + + /// + /// Undocumented function. + /// + /// The pin. + /// The freq. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)] + public static extern Int32 PwmToneWrite(Int32 pin, Int32 freq); + + /// + /// This writes the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware. + /// + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)] + public static extern void DigitalWriteByte(Int32 value); + + /// + /// This writes the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware. + /// + /// The value. + [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)] + public static extern void DigitalWriteByte2(Int32 value); + + /// + /// Undocumented function + /// This reads the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to get all 8 bits at once to a particular value. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)] + public static extern UInt32 DigitalReadByte(); + + /// + /// Undocumented function + /// This reads the 8-bit byte supplied to the first 8 GPIO pins. + /// It’s the fastest way to get all 8 bits at once to a particular value. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)] + public static extern UInt32 DigitalReadByte2(); + + /// + /// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional, + /// however the default mode in the Pi is “balanced”. You can switch modes by supplying the parameter: PWM_MODE_BAL or PWM_MODE_MS. + /// + /// The mode. + [DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)] + public static extern void PwmSetMode(Int32 mode); + + /// + /// This sets the range register in the PWM generator. The default is 1024. + /// + /// The range. + [DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)] + public static extern void PwmSetRange(UInt32 range); + + /// + /// This sets the divisor for the PWM clock. + /// Note: The PWM control functions can not be used when in Sys mode. + /// To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual. + /// + /// The divisor. + [DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)] + public static extern void PwmSetClock(Int32 divisor); + + /// + /// Undocumented function. + /// + /// The pin. + /// The freq. + [DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)] + public static extern void GpioClockSet(Int32 pin, Int32 freq); + + /// + /// This function registers a function to received interrupts on the specified pin. + /// The edgeType parameter is either INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH or INT_EDGE_SETUP. + /// If it is INT_EDGE_SETUP then no initialisation of the pin will happen – it’s assumed that you have already setup the pin elsewhere + /// (e.g. with the gpio program), but if you specify one of the other types, then the pin will be exported and initialised as specified. + /// This is accomplished via a suitable call to the gpio utility program, so it need to be available. + /// The pin number is supplied in the current mode – native wiringPi, BCM_GPIO, physical or Sys modes. + /// This function will work in any mode, and does not need root privileges to work. + /// The function will be called when the interrupt triggers. When it is triggered, it’s cleared in the dispatcher before calling your function, + /// so if a subsequent interrupt fires before you finish your handler, then it won’t be missed. (However it can only track one more interrupt, + /// if more than one interrupt fires while one is being handled then they will be ignored) + /// This function is run at a high priority (if the program is run using sudo, or as root) and executes concurrently with the main program. + /// It has full access to all the global variables, open file handles and so on. + /// + /// The pin. + /// The mode. + /// The method. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)] + public static extern Int32 WiringPiISR(Int32 pin, Int32 mode, InterruptServiceRoutineCallback method); + + /// + /// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration. + /// This function is then run concurrently with your main program. An example may be to have this function wait for an interrupt while + /// your program carries on doing other tasks. The thread can indicate an event, or action by using global variables to + /// communicate back to the main program, or other threads. + /// + /// The method. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)] + public static extern Int32 PiThreadCreate(ThreadWorker method); + + /// + /// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key. + /// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key. + /// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread + /// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data – + /// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example. + /// + /// The key. + [DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)] + public static extern void PiLock(Int32 key); + + /// + /// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key. + /// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key. + /// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread + /// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data – + /// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example. + /// + /// The key. + [DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)] + public static extern void PiUnlock(Int32 key); + + /// + /// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority + /// and enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum). + /// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs are running. + /// The priority parameter works relative to others – so you can make one program priority 1 and another priority 2 + /// and it will have the same effect as setting one to 10 and the other to 90 (as long as no other + /// programs are running with elevated priorities) + /// The return value is 0 for success and -1 for error. If an error is returned, the program should then consult the errno global variable, as per the usual conventions. + /// Note: Only programs running as root can change their priority. If called from a non-root program then nothing happens. + /// + /// The priority. + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)] + public static extern Int32 PiHiPri(Int32 priority); + + /// + /// This causes program execution to pause for at least howLong milliseconds. + /// Due to the multi-tasking nature of Linux it could be longer. + /// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days. + /// + /// The how long. + [DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)] + public static extern void Delay(UInt32 howLong); + + /// + /// This causes program execution to pause for at least howLong microseconds. + /// Due to the multi-tasking nature of Linux it could be longer. + /// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes. + /// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time, + /// Delays over 100 microseconds are done using the system nanosleep() function – You may need to consider the implications + /// of very short delays on the overall performance of the system, especially if using threads. + /// + /// The how long. + [DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)] + public static extern void DelayMicroseconds(UInt32 howLong); + + /// + /// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions. + /// It returns an unsigned 32-bit number which wraps after 49 days. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)] + public static extern UInt32 Millis(); + + /// + /// This returns a number representing the number of microseconds since your program called one of + /// the wiringPiSetup functions. It returns an unsigned 32-bit number which wraps after approximately 71 minutes. + /// + /// The result code. + [DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)] + public static extern UInt32 Micros(); + + #endregion + } } \ No newline at end of file diff --git a/Unosquare.WiringPi/Resources/EmbeddedResources.cs b/Unosquare.WiringPi/Resources/EmbeddedResources.cs index efd28eb..0749aef 100644 --- a/Unosquare.WiringPi/Resources/EmbeddedResources.cs +++ b/Unosquare.WiringPi/Resources/EmbeddedResources.cs @@ -1,65 +1,56 @@ -namespace Unosquare.WiringPi.Resources -{ - using Native; - using System; - using System.Collections.ObjectModel; - using System.IO; - using System.Reflection; - +using System; +using System.Collections.ObjectModel; +using System.IO; +using System.Reflection; + +using Unosquare.WiringPi.Native; + +namespace Unosquare.WiringPi.Resources { + /// + /// Provides access to embedded assembly files. + /// + internal static class EmbeddedResources { /// - /// Provides access to embedded assembly files. + /// Initializes static members of the class. /// - internal static class EmbeddedResources - { - /// - /// Initializes static members of the class. - /// - static EmbeddedResources() - { - ResourceNames = - new ReadOnlyCollection(typeof(EmbeddedResources).Assembly.GetManifestResourceNames()); - } - - /// - /// Gets the resource names. - /// - /// - /// The resource names. - /// - public static ReadOnlyCollection ResourceNames { get; } - - /// - /// Extracts all the file resources to the specified base path. - /// - public static void ExtractAll() - { - var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - var executablePermissions = SysCall.StringToInteger("0777", IntPtr.Zero, 8); - - foreach (var resourceName in ResourceNames) - { - var filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length); - var targetPath = Path.Combine(basePath, filename); - if (File.Exists(targetPath)) return; - - using (var stream = typeof(EmbeddedResources).Assembly - .GetManifestResourceStream(resourceName)) - { - using (var outputStream = File.OpenWrite(targetPath)) - { - stream?.CopyTo(outputStream); - } - - try - { - SysCall.Chmod(targetPath, (uint)executablePermissions); - } - catch - { - /* Ignore */ - } - } - } - } - } + static EmbeddedResources() => ResourceNames = new ReadOnlyCollection(typeof(EmbeddedResources).Assembly.GetManifestResourceNames()); + + /// + /// Gets the resource names. + /// + /// + /// The resource names. + /// + public static ReadOnlyCollection ResourceNames { + get; + } + + /// + /// Extracts all the file resources to the specified base path. + /// + public static void ExtractAll() { + String basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + Int32 executablePermissions = SysCall.StringToInteger("0777", IntPtr.Zero, 8); + + foreach(String resourceName in ResourceNames) { + String filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length); + String targetPath = Path.Combine(basePath, filename); + if(File.Exists(targetPath)) { + return; + } + + using(Stream stream = typeof(EmbeddedResources).Assembly.GetManifestResourceStream(resourceName)) { + using(FileStream outputStream = File.OpenWrite(targetPath)) { + stream?.CopyTo(outputStream); + } + + try { + _ = SysCall.Chmod(targetPath, (UInt32)executablePermissions); + } catch { + /* Ignore */ + } + } + } + } + } } \ No newline at end of file diff --git a/Unosquare.WiringPi/SpiBus.cs b/Unosquare.WiringPi/SpiBus.cs index cecb167..19a0f95 100644 --- a/Unosquare.WiringPi/SpiBus.cs +++ b/Unosquare.WiringPi/SpiBus.cs @@ -1,43 +1,45 @@ -namespace Unosquare.WiringPi -{ - using RaspberryIO.Abstractions; - - /// - /// The SPI Bus containing the 2 SPI channels. - /// - public class SpiBus : ISpiBus - { - /// - public int Channel0Frequency { get; set; } - - /// - public int Channel1Frequency { get; set; } - - /// - public int DefaultFrequency => 8000000; - - /// - public ISpiChannel Channel0 - { - get - { - if (Channel0Frequency == 0) - Channel0Frequency = DefaultFrequency; - - return SpiChannel.Retrieve(SpiChannelNumber.Channel0, Channel0Frequency); - } - } - - /// - public ISpiChannel Channel1 - { - get - { - if (Channel1Frequency == 0) - Channel1Frequency = DefaultFrequency; - - return SpiChannel.Retrieve(SpiChannelNumber.Channel1, Channel1Frequency); - } - } - } +using System; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// The SPI Bus containing the 2 SPI channels. + /// + public class SpiBus : ISpiBus { + /// + public Int32 Channel0Frequency { + get; set; + } + + /// + public Int32 Channel1Frequency { + get; set; + } + + /// + public Int32 DefaultFrequency => 8000000; + + /// + public ISpiChannel Channel0 { + get { + if(this.Channel0Frequency == 0) { + this.Channel0Frequency = this.DefaultFrequency; + } + + return SpiChannel.Retrieve(SpiChannelNumber.Channel0, this.Channel0Frequency); + } + } + + /// + public ISpiChannel Channel1 { + get { + if(this.Channel1Frequency == 0) { + this.Channel1Frequency = this.DefaultFrequency; + } + + return SpiChannel.Retrieve(SpiChannelNumber.Channel1, this.Channel1Frequency); + } + } + } } diff --git a/Unosquare.WiringPi/SpiChannel.cs b/Unosquare.WiringPi/SpiChannel.cs index b85f01d..4c9c507 100644 --- a/Unosquare.WiringPi/SpiChannel.cs +++ b/Unosquare.WiringPi/SpiChannel.cs @@ -1,130 +1,131 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using RaspberryIO.Abstractions.Native; - using Swan; - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using Swan; + +using Unosquare.RaspberryIO.Abstractions; +using Unosquare.RaspberryIO.Abstractions.Native; + +namespace Unosquare.WiringPi { + /// + /// Provides access to using the SPI buses on the GPIO. + /// SPI is a bus that works like a ring shift register + /// The number of bytes pushed is equal to the number of bytes received. + /// + public sealed class SpiChannel : ISpiChannel { /// - /// Provides access to using the SPI buses on the GPIO. - /// SPI is a bus that works like a ring shift register - /// The number of bytes pushed is equal to the number of bytes received. + /// The minimum frequency of a SPI Channel. /// - public sealed class SpiChannel : ISpiChannel - { - /// - /// The minimum frequency of a SPI Channel. - /// - public const int MinFrequency = 500000; - - /// - /// The maximum frequency of a SPI channel. - /// - public const int MaxFrequency = 32000000; - - private static readonly object SyncRoot = new object(); - private static readonly Dictionary Buses = new Dictionary(); - private readonly object _syncLock = new object(); - - /// - /// Initializes a new instance of the class. - /// - /// The channel. - /// The frequency. - private SpiChannel(SpiChannelNumber channel, int frequency) - { - lock (SyncRoot) - { - Frequency = frequency.Clamp(MinFrequency, MaxFrequency); - Channel = (int)channel; - FileDescriptor = WiringPi.WiringPiSPISetup((int)channel, Frequency); - - if (FileDescriptor < 0) - { - HardwareException.Throw(nameof(SpiChannel), channel.ToString()); - } - } - } - - /// - public int FileDescriptor { get; } - - /// - public int Channel { get; } - - /// - public int Frequency { get; } - - /// - public byte[] SendReceive(byte[] buffer) - { - if (buffer == null || buffer.Length == 0) - return null; - - lock (_syncLock) - { - var spiBuffer = new byte[buffer.Length]; - Array.Copy(buffer, spiBuffer, buffer.Length); - - var result = WiringPi.WiringPiSPIDataRW(Channel, spiBuffer, spiBuffer.Length); - if (result < 0) HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive)); - - return spiBuffer; - } - } - - /// - /// Sends data and simultaneously receives the data in the return buffer. - /// - /// The buffer. - /// - /// The read bytes from the ring-style bus. - /// - public Task SendReceiveAsync(byte[] buffer) => Task.Run(() => SendReceive(buffer)); - - /// - public void Write(byte[] buffer) - { - lock (_syncLock) - { - var result = SysCall.Write(FileDescriptor, buffer, buffer.Length); - - if (result < 0) - HardwareException.Throw(nameof(SpiChannel), nameof(Write)); - } - } - - /// - /// Writes the specified buffer the the underlying FileDescriptor. - /// Do not use this method if you expect data back. - /// This method is efficient if used in a fire-and-forget scenario - /// like sending data over to those long RGB LED strips. - /// - /// The buffer. - /// The awaitable task. - public Task WriteAsync(byte[] buffer) => Task.Run(() => { Write(buffer); }); - - /// - /// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically. - /// If it had been previously registered, then the bus is simply returned. - /// - /// The channel. - /// The frequency. - /// The usable SPI channel. - internal static ISpiChannel Retrieve(SpiChannelNumber channel, int frequency) - { - lock (SyncRoot) - { - if (Buses.ContainsKey(channel)) - return Buses[channel]; - - var newBus = new SpiChannel(channel, frequency); - Buses[channel] = newBus; - return newBus; - } - } - } + public const Int32 MinFrequency = 500000; + + /// + /// The maximum frequency of a SPI channel. + /// + public const Int32 MaxFrequency = 32000000; + + private static readonly Object SyncRoot = new Object(); + private static readonly Dictionary Buses = new Dictionary(); + private readonly Object _syncLock = new Object(); + + /// + /// Initializes a new instance of the class. + /// + /// The channel. + /// The frequency. + private SpiChannel(SpiChannelNumber channel, Int32 frequency) { + lock(SyncRoot) { + this.Frequency = frequency.Clamp(MinFrequency, MaxFrequency); + this.Channel = (Int32)channel; + this.FileDescriptor = Native.WiringPi.WiringPiSPISetup((Int32)channel, this.Frequency); + + if(this.FileDescriptor < 0) { + HardwareException.Throw(nameof(SpiChannel), channel.ToString()); + } + } + } + + /// + public Int32 FileDescriptor { + get; + } + + /// + public Int32 Channel { + get; + } + + /// + public Int32 Frequency { + get; + } + + /// + public Byte[] SendReceive(Byte[] buffer) { + if(buffer == null || buffer.Length == 0) { + return null; + } + + lock(this._syncLock) { + Byte[] spiBuffer = new Byte[buffer.Length]; + Array.Copy(buffer, spiBuffer, buffer.Length); + + Int32 result = Native.WiringPi.WiringPiSPIDataRW(this.Channel, spiBuffer, spiBuffer.Length); + if(result < 0) { + HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive)); + } + + return spiBuffer; + } + } + + /// + /// Sends data and simultaneously receives the data in the return buffer. + /// + /// The buffer. + /// + /// The read bytes from the ring-style bus. + /// + public Task SendReceiveAsync(Byte[] buffer) => Task.Run(() => this.SendReceive(buffer)); + + /// + public void Write(Byte[] buffer) { + lock(this._syncLock) { + Int32 result = Native.SysCall.Write(this.FileDescriptor, buffer, buffer.Length); + + if(result < 0) { + HardwareException.Throw(nameof(SpiChannel), nameof(Write)); + } + } + } + + /// + /// Writes the specified buffer the the underlying FileDescriptor. + /// Do not use this method if you expect data back. + /// This method is efficient if used in a fire-and-forget scenario + /// like sending data over to those long RGB LED strips. + /// + /// The buffer. + /// The awaitable task. + public Task WriteAsync(Byte[] buffer) => Task.Run(() => { this.Write(buffer); }); + + /// + /// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically. + /// If it had been previously registered, then the bus is simply returned. + /// + /// The channel. + /// The frequency. + /// The usable SPI channel. + internal static ISpiChannel Retrieve(SpiChannelNumber channel, Int32 frequency) { + lock(SyncRoot) { + if(Buses.ContainsKey(channel)) { + return Buses[channel]; + } + + SpiChannel newBus = new SpiChannel(channel, frequency); + Buses[channel] = newBus; + return newBus; + } + } + } } diff --git a/Unosquare.WiringPi/SystemInfo.cs b/Unosquare.WiringPi/SystemInfo.cs index 55f0938..dc4314e 100644 --- a/Unosquare.WiringPi/SystemInfo.cs +++ b/Unosquare.WiringPi/SystemInfo.cs @@ -1,45 +1,42 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using System; - - /// - /// Represents the WiringPi system info. - /// - /// - public class SystemInfo : ISystemInfo - { - private static readonly object Lock = new object(); - private static bool _revGetted; - private static BoardRevision _boardRevision = BoardRevision.Rev2; - - /// - public BoardRevision BoardRevision => GetBoardRevision(); - - /// - public Version LibraryVersion - { - get - { - var libParts = WiringPi.WiringPiLibrary.Split('.'); - var major = int.Parse(libParts[libParts.Length - 2]); - var minor = int.Parse(libParts[libParts.Length - 1]); - return new Version(major, minor); - } - } - - internal static BoardRevision GetBoardRevision() - { - lock (Lock) - { - if (_revGetted) return _boardRevision; - var val = WiringPi.PiBoardRev(); - _boardRevision = val == 1 ? BoardRevision.Rev1 : BoardRevision.Rev2; - _revGetted = true; - } - - return _boardRevision; - } - } +using System; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// Represents the WiringPi system info. + /// + /// + public class SystemInfo : ISystemInfo { + private static readonly Object Lock = new Object(); + private static Boolean _revGetted; + private static BoardRevision _boardRevision = BoardRevision.Rev2; + + /// + public BoardRevision BoardRevision => GetBoardRevision(); + + /// + public Version LibraryVersion { + get { + String[] libParts = Native.WiringPi.WiringPiLibrary.Split('.'); + Int32 major = Int32.Parse(libParts[libParts.Length - 2]); + Int32 minor = Int32.Parse(libParts[libParts.Length - 1]); + return new Version(major, minor); + } + } + + internal static BoardRevision GetBoardRevision() { + lock(Lock) { + if(_revGetted) { + return _boardRevision; + } + + Int32 val = Native.WiringPi.PiBoardRev(); + _boardRevision = val == 1 ? BoardRevision.Rev1 : BoardRevision.Rev2; + _revGetted = true; + } + + return _boardRevision; + } + } } diff --git a/Unosquare.WiringPi/Threading.cs b/Unosquare.WiringPi/Threading.cs index ada771e..474179f 100644 --- a/Unosquare.WiringPi/Threading.cs +++ b/Unosquare.WiringPi/Threading.cs @@ -1,72 +1,71 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - using RaspberryIO.Abstractions.Native; - using Swan; - using System; - +using System; + +using Swan; + +using Unosquare.RaspberryIO.Abstractions; +using Unosquare.RaspberryIO.Abstractions.Native; + +namespace Unosquare.WiringPi { + /// + /// Use this class to access threading methods using interop. + /// + /// + public class Threading : IThreading { /// - /// Use this class to access threading methods using interop. + /// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and + /// enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum). + /// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs + /// are running. The priority parameter works relative to others – so you can make one program priority 1 and + /// another priority 2 and it will have the same effect as setting one to 10 and the other to 90 + /// (as long as no other programs are running with elevated priorities). /// - /// - public class Threading : IThreading - { - /// - /// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and - /// enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum). - /// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs - /// are running. The priority parameter works relative to others – so you can make one program priority 1 and - /// another priority 2 and it will have the same effect as setting one to 10 and the other to 90 - /// (as long as no other programs are running with elevated priorities). - /// - /// The priority. - public void SetThreadPriority(int priority) - { - priority = priority.Clamp(0, 99); - var result = WiringPi.PiHiPri(priority); - if (result < 0) HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority)); - } - - /// - /// These allow you to synchronize variable updates from your main program to any threads running in your program. - /// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key, - /// it will be stalled until the first process has unlocked the same key. - /// - /// The key. - public void Lock(ThreadLockKey key) => WiringPi.PiLock((int)key); - - /// - /// These allow you to synchronize variable updates from your main program to any threads running in your program. - /// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key, - /// it will be stalled until the first process has unlocked the same key. - /// - /// The key. - public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((int)key); - - /// - /// - /// This is really nothing more than a simplified interface to the Posix threads mechanism that Linux supports. - /// See the manual pages on Posix threads (man pthread) if you need more control over them. - /// - /// worker. - public void StartThread(Action worker) - { - if (worker == null) - throw new ArgumentNullException(nameof(worker)); - - var result = WiringPi.PiThreadCreate(new ThreadWorker(worker)); - - if (result != 0) - HardwareException.Throw(nameof(Timing), nameof(StartThread)); - } - - /// - public UIntPtr StartThreadEx(Action worker, UIntPtr userData) => - throw new NotSupportedException("WiringPi does only support a simple thread callback that has no parameters."); - - /// - public void StopThreadEx(UIntPtr handle) => - throw new NotSupportedException("WiringPi does not support stopping threads."); - } + /// The priority. + public void SetThreadPriority(Int32 priority) { + priority = priority.Clamp(0, 99); + Int32 result = Native.WiringPi.PiHiPri(priority); + if(result < 0) { + HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority)); + } + } + + /// + /// These allow you to synchronize variable updates from your main program to any threads running in your program. + /// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key, + /// it will be stalled until the first process has unlocked the same key. + /// + /// The key. + public void Lock(ThreadLockKey key) => Native.WiringPi.PiLock((Int32)key); + + /// + /// These allow you to synchronize variable updates from your main program to any threads running in your program. + /// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key, + /// it will be stalled until the first process has unlocked the same key. + /// + /// The key. + public void Unlock(ThreadLockKey key) => Native.WiringPi.PiUnlock((Int32)key); + + /// + /// + /// This is really nothing more than a simplified interface to the Posix threads mechanism that Linux supports. + /// See the manual pages on Posix threads (man pthread) if you need more control over them. + /// + /// worker. + public void StartThread(Action worker) { + if(worker == null) { + throw new ArgumentNullException(nameof(worker)); + } + + Int32 result = Native.WiringPi.PiThreadCreate(new Native.ThreadWorker(worker)); + + if(result != 0) { + HardwareException.Throw(nameof(Timing), nameof(StartThread)); + } + } + + /// + public UIntPtr StartThreadEx(Action worker, UIntPtr userData) => throw new NotSupportedException("WiringPi does only support a simple thread callback that has no parameters."); + + /// + public void StopThreadEx(UIntPtr handle) => throw new NotSupportedException("WiringPi does not support stopping threads."); + } } diff --git a/Unosquare.WiringPi/Timing.cs b/Unosquare.WiringPi/Timing.cs index de36444..8756ead 100644 --- a/Unosquare.WiringPi/Timing.cs +++ b/Unosquare.WiringPi/Timing.cs @@ -1,36 +1,35 @@ -namespace Unosquare.WiringPi -{ - using Native; - using RaspberryIO.Abstractions; - +using System; + +using Unosquare.RaspberryIO.Abstractions; + +namespace Unosquare.WiringPi { + /// + /// Provides access to timing and threading properties and methods. + /// + public class Timing : ITiming { + /// /// - /// Provides access to timing and threading properties and methods. + /// This returns a number representing the number of milliseconds since your program + /// initialized the GPIO controller. + /// It returns an unsigned 32-bit number which wraps after 49 days. /// - public class Timing : ITiming - { - /// - /// - /// This returns a number representing the number of milliseconds since your program - /// initialized the GPIO controller. - /// It returns an unsigned 32-bit number which wraps after 49 days. - /// - public uint Milliseconds => WiringPi.Millis(); - - /// - /// - /// This returns a number representing the number of microseconds since your - /// program initialized the GPIO controller - /// It returns an unsigned 32-bit number which wraps after approximately 71 minutes. - /// - public uint Microseconds => WiringPi.Micros(); - - /// - public static void Sleep(uint millis) => WiringPi.Delay(millis); - - /// - public void SleepMilliseconds(uint millis) => Sleep(millis); - - /// - public void SleepMicroseconds(uint micros) => WiringPi.DelayMicroseconds(micros); - } + public UInt32 Milliseconds => Native.WiringPi.Millis(); + + /// + /// + /// This returns a number representing the number of microseconds since your + /// program initialized the GPIO controller + /// It returns an unsigned 32-bit number which wraps after approximately 71 minutes. + /// + public UInt32 Microseconds => Native.WiringPi.Micros(); + + /// + public static void Sleep(UInt32 millis) => Native.WiringPi.Delay(millis); + + /// + public void SleepMilliseconds(UInt32 millis) => Sleep(millis); + + /// + public void SleepMicroseconds(UInt32 micros) => Native.WiringPi.DelayMicroseconds(micros); + } }