Coding styles
This commit is contained in:
+541
-554
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,201 +1,167 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using System;
|
||||
|
||||
public partial class GpioPin
|
||||
{
|
||||
#region Static Pin Definitions
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 2 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 3 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
|
||||
Name = "BCM 4 (GPCLK0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
|
||||
Name = "BCM 17"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 27"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 22"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 10 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 9 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 11 (SCLCK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.I2CSDA },
|
||||
Name = "BCM 0 (ID_SD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.I2CSCL },
|
||||
Name = "BCM 1 (ID_SC)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 7 (CE1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 8 (CE0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 25"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 24"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 23"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 18 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.UARTRXD },
|
||||
Name = "BCM 15 (RXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.UARTTXD },
|
||||
Name = "BCM 14 (TXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 5"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 6"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 13 (PWM1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 19 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 26"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 21 (SCLK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 20 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 16"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 12 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 28 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 29 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 30"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6)
|
||||
{
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 31"
|
||||
});
|
||||
|
||||
#endregion
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
public partial class GpioPin {
|
||||
#region Static Pin Definitions
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 2 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 3 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
|
||||
Name = "BCM 4 (GPCLK0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
|
||||
Name = "BCM 17"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 27"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 22"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 10 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 9 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 11 (SCLCK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27) {
|
||||
Capabilities = new[] { PinCapability.I2CSDA },
|
||||
Name = "BCM 0 (ID_SD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28) {
|
||||
Capabilities = new[] { PinCapability.I2CSCL },
|
||||
Name = "BCM 1 (ID_SC)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 7 (CE1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 8 (CE0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 25"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 24"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 23"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 18 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10) {
|
||||
Capabilities = new[] { PinCapability.UARTRXD },
|
||||
Name = "BCM 15 (RXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8) {
|
||||
Capabilities = new[] { PinCapability.UARTTXD },
|
||||
Name = "BCM 14 (TXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 5"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 6"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 13 (PWM1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 19 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 26"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 21 (SCLK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 20 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 16"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 12 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 28 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 29 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 30"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 31"
|
||||
});
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,93 +1,87 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
||||
/// </summary>
|
||||
public class I2CBus : SingletonBase<I2CBus>
|
||||
{
|
||||
// TODO: It would be nice to integrate i2c device detection.
|
||||
private static readonly object SyncRoot = new object();
|
||||
private readonly Dictionary<int, I2CDevice> _devices = new Dictionary<int, I2CDevice>();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
||||
/// </summary>
|
||||
private I2CBus()
|
||||
{
|
||||
// placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered devices as a read only collection.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(_devices.Values.ToArray());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="I2CDevice"/>.
|
||||
/// </value>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>A reference to an I2C device</returns>
|
||||
public I2CDevice this[int deviceId] => GetDeviceById(deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device by identifier.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
public I2CDevice GetDeviceById(int deviceId)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return _devices[deviceId];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a device to the bus by its Id. If the device is already registered it simply returns the existing device.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
||||
public I2CDevice 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The Linux file handle</returns>
|
||||
private static int SetupFileDescriptor(int deviceId)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return WiringPi.WiringPiI2CSetup(deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
||||
/// </summary>
|
||||
public class I2CBus : SingletonBase<I2CBus> {
|
||||
// TODO: It would be nice to integrate i2c device detection.
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private readonly Dictionary<Int32, I2CDevice> _devices = new Dictionary<Int32, I2CDevice>();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
||||
/// </summary>
|
||||
private I2CBus() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered devices as a read only collection.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(this._devices.Values.ToArray());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="I2CDevice"/>.
|
||||
/// </value>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>A reference to an I2C device</returns>
|
||||
public I2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device by identifier.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
public I2CDevice GetDeviceById(Int32 deviceId) {
|
||||
lock(SyncRoot) {
|
||||
return this._devices[deviceId];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a device to the bus by its Id. If the device is already registered it simply returns the existing device.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
||||
public I2CDevice 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The Linux file handle</returns>
|
||||
private static Int32 SetupFileDescriptor(Int32 deviceId) {
|
||||
lock(SyncRoot) {
|
||||
return WiringPi.WiringPiI2CSetup(deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,195 +1,193 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Native;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a device on the I2C Bus
|
||||
/// </summary>
|
||||
public class I2CDevice
|
||||
{
|
||||
private readonly object _syncLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <param name="fileDescriptor">The file descriptor.</param>
|
||||
internal I2CDevice(int deviceId, int fileDescriptor)
|
||||
{
|
||||
DeviceId = deviceId;
|
||||
FileDescriptor = fileDescriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device identifier.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The device identifier.
|
||||
/// </value>
|
||||
public int DeviceId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard POSIX file descriptor.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public int FileDescriptor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public byte Read()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CRead(FileDescriptor);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
return (byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public Task<byte> ReadAsync() => Task.Run(() => Read());
|
||||
|
||||
/// <summary>
|
||||
/// Reads a buffer of the specified length, one byte at a time
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a buffer of the specified length, one byte at a time
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
public Task<byte[]> ReadAsync(int length) => Task.Run(() => Read(length));
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(byte data)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, data);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte data) => Task.Run(() => { Write(data); });
|
||||
|
||||
/// <summary>
|
||||
/// Writes a set of bytes to the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a set of bytes to the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte[] data)
|
||||
{
|
||||
return Task.Run(() => { Write(data); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These read an 8 or 16-bit value from the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address byte from device</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These read an 8 or 16-bit value from the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address word from device</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Represents a device on the I2C Bus
|
||||
/// </summary>
|
||||
public class I2CDevice {
|
||||
private readonly Object _syncLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <param name="fileDescriptor">The file descriptor.</param>
|
||||
internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) {
|
||||
this.DeviceId = deviceId;
|
||||
this.FileDescriptor = fileDescriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device identifier.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The device identifier.
|
||||
/// </value>
|
||||
public Int32 DeviceId {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard POSIX file descriptor.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public Int32 FileDescriptor {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public Byte Read() {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
}
|
||||
|
||||
return (Byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public Task<Byte> ReadAsync() => Task.Run(() => this.Read());
|
||||
|
||||
/// <summary>
|
||||
/// Reads a buffer of the specified length, one byte at a time
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
public Byte[] Read(Int32 length) {
|
||||
lock(this._syncLock) {
|
||||
Byte[] buffer = new Byte[length];
|
||||
for(Int32 i = 0; i < length; i++) {
|
||||
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
}
|
||||
|
||||
buffer[i] = (Byte)result;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a buffer of the specified length, one byte at a time
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
public Task<Byte[]> ReadAsync(Int32 length) => Task.Run(() => this.Read(length));
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(Byte data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(Byte data) => Task.Run(() => this.Write(data));
|
||||
|
||||
/// <summary>
|
||||
/// Writes a set of bytes to the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(Byte[] data) {
|
||||
lock(this._syncLock) {
|
||||
foreach(Byte b in data) {
|
||||
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, b);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a set of bytes to the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data));
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
public void WriteAddressByte(Int32 address, Byte data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
public void WriteAddressWord(Int32 address, UInt16 data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These read an 8 or 16-bit value from the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address byte from device</returns>
|
||||
public Byte ReadAddressByte(Int32 address) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
||||
}
|
||||
|
||||
return (Byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These read an 8 or 16-bit value from the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address word from device</returns>
|
||||
public UInt16 ReadAddressWord(Int32 address) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
||||
}
|
||||
|
||||
return Convert.ToUInt16(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Swan.Abstractions;
|
||||
|
||||
using System;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// The SPI Bus containing the 2 SPI channels
|
||||
/// </summary>
|
||||
public class SpiBus : SingletonBase<SpiBus> {
|
||||
/// <summary>
|
||||
/// The SPI Bus containing the 2 SPI channels
|
||||
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
|
||||
/// </summary>
|
||||
public class SpiBus : SingletonBase<SpiBus>
|
||||
{
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
|
||||
/// </summary>
|
||||
private SpiBus()
|
||||
{
|
||||
// placeholder
|
||||
}
|
||||
|
||||
#region SPI Access
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel 0 frequency in Hz.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel0 frequency.
|
||||
/// </value>
|
||||
public int Channel0Frequency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel0.
|
||||
/// </value>
|
||||
public SpiChannel Channel0
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Channel0Frequency == 0)
|
||||
Channel0Frequency = SpiChannel.DefaultFrequency;
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, Channel0Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel 1 frequency in Hz
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel1 frequency.
|
||||
/// </value>
|
||||
public int Channel1Frequency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel1.
|
||||
/// </value>
|
||||
public SpiChannel Channel1
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Channel1Frequency == 0)
|
||||
Channel1Frequency = SpiChannel.DefaultFrequency;
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, Channel1Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
private SpiBus() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
#region SPI Access
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel 0 frequency in Hz.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel0 frequency.
|
||||
/// </value>
|
||||
public Int32 Channel0Frequency {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel0.
|
||||
/// </value>
|
||||
public SpiChannel Channel0 {
|
||||
get {
|
||||
if(this.Channel0Frequency == 0) {
|
||||
this.Channel0Frequency = SpiChannel.DefaultFrequency;
|
||||
}
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, this.Channel0Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the channel 1 frequency in Hz
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel1 frequency.
|
||||
/// </value>
|
||||
public Int32 Channel1Frequency {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The channel1.
|
||||
/// </value>
|
||||
public SpiChannel Channel1 {
|
||||
get {
|
||||
if(this.Channel1Frequency == 0) {
|
||||
this.Channel1Frequency = SpiChannel.DefaultFrequency;
|
||||
}
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, this.Channel1Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,154 +1,154 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public sealed class SpiChannel {
|
||||
/// <summary>
|
||||
/// 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 an SPI Channel
|
||||
/// </summary>
|
||||
public sealed class SpiChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum frequency of an SPI Channel
|
||||
/// </summary>
|
||||
public const int MinFrequency = 500000;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum frequency of an SPI channel
|
||||
/// </summary>
|
||||
public const int MaxFrequency = 32000000;
|
||||
|
||||
/// <summary>
|
||||
/// The default frequency of SPI channels
|
||||
/// This is set to 8 Mhz wich is typical in modern hardware.
|
||||
/// </summary>
|
||||
public const int DefaultFrequency = 8000000;
|
||||
|
||||
private static readonly object SyncRoot = new object();
|
||||
private static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
|
||||
private readonly object _syncLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpiChannel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard initialization file descriptor.
|
||||
/// anything negative means error.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public int FileDescriptor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
public int Channel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frequency.
|
||||
/// </summary>
|
||||
public int Frequency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sends data and simultaneously receives the data in the return buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The read bytes from the ring-style bus</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data and simultaneously receives the data in the return buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>
|
||||
/// The read bytes from the ring-style bus
|
||||
/// </returns>
|
||||
public Task<byte[]> SendReceiveAsync(byte[] buffer) => Task.Run(() => SendReceive(buffer));
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
public void Write(byte[] buffer)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = Standard.Write(FileDescriptor, buffer, buffer.Length);
|
||||
|
||||
if (result < 0)
|
||||
HardwareException.Throw(nameof(SpiChannel), nameof(Write));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte[] buffer) => Task.Run(() => { Write(buffer); });
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
/// <returns>The usable SPI channel</returns>
|
||||
internal static SpiChannel 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;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum frequency of an SPI channel
|
||||
/// </summary>
|
||||
public const Int32 MaxFrequency = 32000000;
|
||||
|
||||
/// <summary>
|
||||
/// The default frequency of SPI channels
|
||||
/// This is set to 8 Mhz wich is typical in modern hardware.
|
||||
/// </summary>
|
||||
public const Int32 DefaultFrequency = 8000000;
|
||||
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
|
||||
private readonly Object _syncLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpiChannel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
private SpiChannel(SpiChannelNumber channel, Int32 frequency) {
|
||||
lock(SyncRoot) {
|
||||
this.Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
|
||||
this.Channel = (Int32)channel;
|
||||
this.FileDescriptor = WiringPi.WiringPiSPISetup((Int32)channel, this.Frequency);
|
||||
|
||||
if(this.FileDescriptor < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), channel.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard initialization file descriptor.
|
||||
/// anything negative means error.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public Int32 FileDescriptor {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
public Int32 Channel {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frequency.
|
||||
/// </summary>
|
||||
public Int32 Frequency {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data and simultaneously receives the data in the return buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The read bytes from the ring-style bus</returns>
|
||||
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 = WiringPi.WiringPiSPIDataRW(this.Channel, spiBuffer, spiBuffer.Length);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
|
||||
}
|
||||
|
||||
return spiBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data and simultaneously receives the data in the return buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>
|
||||
/// The read bytes from the ring-style bus
|
||||
/// </returns>
|
||||
public Task<Byte[]> SendReceiveAsync(Byte[] buffer) => Task.Run(() => this.SendReceive(buffer));
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
public void Write(Byte[] buffer) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = Standard.Write(this.FileDescriptor, buffer, buffer.Length);
|
||||
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(Byte[] buffer) => Task.Run(() => this.Write(buffer));
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
/// <returns>The usable SPI channel</returns>
|
||||
internal static SpiChannel 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user