File: SPIPortFS
Details
File: SPIPortFS.cs
Date: Thu, Mar 7, 2019
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
/// +------------------------------------------------------------------------------------------------------------------------------+
/// | TERMS OF USE: MIT License |
/// +------------------------------------------------------------------------------------------------------------------------------|
/// |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
/// |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
/// |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
/// |is furnished to do so, subject to the following conditions: |
/// | |
/// |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
/// | |
/// |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
/// |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
/// |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
/// |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
/// +------------------------------------------------------------------------------------------------------------------------------+
namespace BBBCSIO
{
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Provides the SPI Master Input/Output Port functionality for a BeagleBone Black
/// This is the SPIDEV version
///
/// Be aware that you need to ensure the SPI port is configured in the Device
/// Tree before this code will work.
///
/// Also NOTE that you cannot use SPIPORT_1 without disabling the HDMI device
/// as they use some of the same pins.
///
/// Also NOTE that if you use the GPIO based slave select lines you cannot
/// also connect anything to the SPI devices internal CS0 or CS1 slave select
/// lines. These will always be activated on every write irregardless
/// of the GPIO based slave select also asserted. This is just the way the
/// SPIDev driver works.
///
/// </summary>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public class SPIPortFS : PortFS
{
// the SPI port we use
private SPIPortEnum spiPort = SPIPortEnum.SPIPORT_NONE;
// the open slave devices we have created
List<SPISlaveDeviceHandle> openSlaveDevices = new List<SPISlaveDeviceHandle>();
// used for external file open calls
const int O_RDONLY = 0x0;
const int O_WRONLY = 0x1;
const int O_RDWR = 0x2;
const int O_NONBLOCK = 0x0004;
// these magic numbers are defined by the Ioctl driver (spidev in this case)
// to tell it what to do. Each byte and nibble has meaning and it is generally
// built on the fly in a C program by a macro which shifts flags about and OR's
// them together. I have not attempted to reproduce this build here and simply
// use the end result since the resulting value is essentially constant for
// an particular ioctl call to a specific driver type
uint SPI_IOC_WR_MODE = 0x40016b01;
uint SPI_IOC_RD_MODE = 0x80016b01;
uint SPI_IOC_WR_MAX_SPEED_HZ=0x40046b04;
uint SPI_IOC_RD_MAX_SPEED_HZ = 0x80046b04;
uint SPI_IOC_MESSAGE_1 = 0x40206B00;
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Constructor
/// </summary>
/// <param name="spiPortIn">The SPI port we use</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public SPIPortFS(SPIPortEnum spiPortIn) : base(GpioEnum.GPIO_NONE)
{
spiPort = spiPortIn;
// NOTE the port is not opened here as per the usual manner. Because
// each SPI dev device represents a distinct Slave select, we open the
// spidev file on the EnableSPISlaveDevice call();
//Console.WriteLine("SPIPort Starts");
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Writes/Reads a buffer out/in to/from an SPI Slave Device.
///
/// Note that the TO/FROM's and IN/OUT's in the above line are there because
/// the SPI protocol always reads a byte for every byte sent. If you send a
/// byte you get a byte. If you do not sent a byte you will never receive
/// a byte since this code operates as an SPI Master. Thus if you only
/// wish to receive you must send an equivalent number of bytes. The
/// bytes you send are determined by the Slave. Sometimes this is just
/// 0x00 and sometimes it represents an address to read - exactly what you,
/// send is entirely slave device implementation dependent.
///
/// If you only wish to transmit, not receive, just use NULL for your
/// rxBuffer. The SPI port will still receive, of course, but you will
/// not be bothered by it.
///
/// NOTE: the Slave Select is set when you opened the port. The rule is
/// one slave to one SPISlaveDeviceHandle.
///
/// </summary>
/// <param name="ssHandle">The SPI Slave Device handle to write to</param>
/// <param name="txByteBuf">The buffer with bytes to write</param>
/// <param name="rxByteBuf">The buffer with bytes to receive. Can be NULL</param>
/// <param name="numBytes">The number of bytes to send/receive
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public void SPITransfer(SPISlaveDeviceHandle ssHandle, byte[] txByteBuf, byte[] rxByteBuf, int numBytes)
{
int spiFileDescriptor = -1;
int ioctlRetVal = -1;
// sanity check
if (ssHandle == null)
{
throw new Exception ("Null Slave Device Handle");
}
if (txByteBuf == null)
{
throw new Exception ("Null tx buffer");
}
if (numBytes <= 0)
{
throw new Exception ("numBytes <= 0");
}
// set up our file descriptor
// are we an internal chip select type slave device?
if ((ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS0) ||
(ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS1))
{
// yes we are, just use this descriptor
spiFileDescriptor = ssHandle.SpiDevFileDescriptor;
}
else if (ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_GPIO)
{
if (ssHandle.GpioSlaveSelect == null)
{
throw new Exception ("No GPIO Slave Select device found.");
}
// use the descriptor of the first non-GPIO slave select
// we find.
// get first slave device. We need the file descriptor
SPISlaveDeviceHandle firstHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (firstHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled.");
}
// use this descriptor
spiFileDescriptor = firstHandle.SpiDevFileDescriptor;
}
else
{
// should never happen
throw new Exception("unknown slave device type");
}
// the data needs to be in unmanaged global memory
// so the spidev driver can see it. This allocates
// that memory. We MUST release this!
IntPtr txBufPtr = Marshal.AllocHGlobal(numBytes+1);
IntPtr rxBufPtr = Marshal.AllocHGlobal(numBytes+1);
try
{
// copy the data from the tx buffer to our pointer
Marshal.Copy(txByteBuf, 0, txBufPtr, numBytes);
// create and fill in the contents of our transfer struct
spi_ioc_transfer xfer = new spi_ioc_transfer();
xfer.tx_buf = txBufPtr;
xfer.rx_buf = rxBufPtr;
xfer.len = (UInt32)numBytes;
xfer.speed_hz = (UInt16)ssHandle.SpeedInHz;
xfer.delay_usecs = ssHandle.DelayUSecs;
xfer.bits_per_word = ssHandle.BitsPerWord;
xfer.cs_change = ssHandle.CSChange;
xfer.pad = 0;
if (ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_GPIO)
{
// lower the slave select
ssHandle.GpioSlaveSelect.Write(false);
try
{
// this is an external call to the libc.so.6 library
ioctlRetVal = ExternalIoCtl(spiFileDescriptor, SPI_IOC_MESSAGE_1, ref xfer);
}
finally
{
// raise the slave select
ssHandle.GpioSlaveSelect.Write(false);
}
}
else
{
// this is an external call to the libc.so.6 library
ioctlRetVal = ExternalIoCtl(spiFileDescriptor, SPI_IOC_MESSAGE_1, ref xfer);
}
// did the call succeed?
if(ioctlRetVal < 0)
{
// it failed
throw new Exception("ExternalIoCtl on device " + ssHandle.SPISlaveDevice + " failed. retval="+ioctlRetVal.ToString());
}
// did the caller supply a receive buffer
if(rxByteBuf!=null)
{
// yes they did, copy the returned data in
Marshal.Copy(rxBufPtr, rxByteBuf, 0, numBytes);
}
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(txBufPtr);
Marshal.FreeHGlobal(rxBufPtr);
}
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Gets the SPI mode. This is used for all Slave Devices on the port
/// It cannot be individually set on a per slave basis. At least one
/// non-GPIO slave must be enabled
/// </summary>
/// <param name="ssHandle">The SPI Slave Device handle</param>
/// <returns>the spi mode</returns>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public SPIModeEnum GetMode()
{
// get first slave device. We need the file descriptor
SPISlaveDeviceHandle ssHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (ssHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled.");
}
uint mode = 0;
// this is an external call to the libc.so.6 library
int retVal = ExternalIoCtl(ssHandle.SpiDevFileDescriptor, SPI_IOC_RD_MODE, ref mode);
// did the call succeed?
if(retVal < 0)
{
// it failed
throw new Exception("ExternalIoCtl on device " + ssHandle.SPISlaveDevice + " failed. retval="+retVal.ToString());
}
return (SPIModeEnum)mode;
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Sets the SPI mode. This is used for all Slave Devices on the port
/// It cannot be individually set on a per slave basis. At least one
/// non-GPIO slave must be enabled
/// </summary>
/// <param name="spiMode">The spi mode to set</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public void SetMode(SPIModeEnum spiMode)
{
// get first slave device. We need the file descriptor
SPISlaveDeviceHandle ssHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (ssHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled.");
}
// this is an external call to the libc.so.6 library
uint mode = (uint)spiMode;
int retVal = ExternalIoCtl(ssHandle.SpiDevFileDescriptor, SPI_IOC_WR_MODE, ref mode);
// did the call succeed?
if(retVal < 0)
{
// it failed
throw new Exception("ExternalIoCtl on device " + ssHandle.SPISlaveDevice + " failed. retval="+retVal.ToString());
}
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Gets the Default SPI speed in Hertz. This value can be overridden on
/// a per slave basis by setting the SpeedInHz in the SPISlaveDeviceHandle
/// </summary>
/// <returns>the spi port speed in Hertz</returns>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public uint GetDefaultSpeedInHz()
{
// get first slave device. We need the file descriptor
SPISlaveDeviceHandle ssHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (ssHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled.");
}
uint speedInHz = 0;
// this is an external call to the libc.so.6 library
int retVal = ExternalIoCtl(ssHandle.SpiDevFileDescriptor, SPI_IOC_RD_MAX_SPEED_HZ, ref speedInHz);
// did the call succeed?
if(retVal < 0)
{
// it failed
throw new Exception("ExternalIoCtl on device " + ssHandle.SPISlaveDevice + " failed. retval="+retVal.ToString());
}
return speedInHz;
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Sets the Default SPI speed in Hertz. This value can be overridden on
/// a per slave basis by setting the SpeedInHz in the SPISlaveDeviceHandle
/// </summary>
/// <param name="spiSpeedInHz">The speed in Hertz to set</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public void SetDefaultSpeedInHz(uint spiSpeedInHz)
{
// get first slave device. We need the file descriptor
SPISlaveDeviceHandle ssHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (ssHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled.");
}
// this is an external call to the libc.so.6 library
uint speedInHz = (uint)spiSpeedInHz;
int retVal = ExternalIoCtl(ssHandle.SpiDevFileDescriptor, SPI_IOC_WR_MAX_SPEED_HZ, ref speedInHz);
// did the call succeed?
if(retVal < 0)
{
// it failed
throw new Exception("ExternalIoCtl on device " + ssHandle.SPISlaveDevice + " failed. retval="+retVal.ToString());
}
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Gets the first SPISlaveDeviceHandle which has a file descriptor. We need
/// at least one of these to access the port even if we are using a GPIO based
/// Slave Select
/// </summary>
/// <returns>ssHandle - the handle for the Slave Device or null for fail</returns>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
private SPISlaveDeviceHandle GetFirstSlaveDeviceWithFD()
{
if (openSlaveDevices == null) return null;
// check each slave device
foreach(SPISlaveDeviceHandle ssHandle in openSlaveDevices)
{
if (ssHandle.SpiDevFileDescriptor >= 0) return ssHandle;
}
return null;
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Enables the SPI slave device. Will throw exceptions if it cannot open the
/// device
/// </summary>
/// <returns>ssHandle - the handle for the Slave Device or null for fail</returns>
/// <param name="spiSlaveDeviceIn">The SPI Slave Device we are configuring</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public SPISlaveDeviceHandle EnableSPISlaveDevice(SPISlaveDeviceEnum spiSlaveDeviceIn)
{
string deviceFileName;
// set up now
deviceFileName = BBBDefinitions.SPIDEV_FILENAME;
// set up the spi device number, this is based off the port
// NOTE that SPI port 0 goes to /dev/spidev1.x and SPI port 1
// goes to /dev/spidev2.x. That is just the way it is
if (SPIPort == SPIPortEnum.SPIPORT_0)
{
deviceFileName = deviceFileName.Replace("%device%", "1");
}
else if (SPIPort == SPIPortEnum.SPIPORT_1)
{
deviceFileName = deviceFileName.Replace("%device%", "2");
}
else
{
// should never happen
throw new Exception ("Unknown SPI Port:" + SPIPort.ToString());
}
// set up the spi slave number
if (spiSlaveDeviceIn == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS0)
{
deviceFileName = deviceFileName.Replace("%slave%", "0");
}
else if (spiSlaveDeviceIn == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS1)
{
deviceFileName = deviceFileName.Replace("%slave%", "1");
}
else
{
// should never happen
throw new Exception ("Unknown SPI Slave Device:" + spiSlaveDeviceIn.ToString());
}
// we open the file. We have to have an open file descriptor
// note this is an external call. It has to be because the
// ioctl needs an open file descriptor it can use
int fd = ExternalFileOpen(deviceFileName, O_RDWR|O_NONBLOCK);
if(fd <= 0)
{
throw new Exception("Could not open spidev file:" + deviceFileName);
}
//Console.WriteLine("SPIPort Slave Device Enabled: "+ deviceFileName);
// create a new slave device handle
SPISlaveDeviceHandle outHandle = new SPISlaveDeviceHandle(spiSlaveDeviceIn, fd);
// record that we opened this slave device (so we can close it later)
openSlaveDevices.Add(outHandle);
// return the slave device handle
return outHandle;
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Enables the SPI slave device which uses a GPIO pin as a slave select.
///
/// NOTE on how this works. When using a GPIO pin as a slave select line
/// we still need to open a SPIDev device because we need a device to
/// send the data to. The way SPIDev works each spidev device is
/// fundamentally associated with a particular slave select line and
/// this cannot be changed. The GPIO line will be used as a separate
/// slave select but the spidev device specific slave select will also
/// be asserted whenever the device is writtent to.
///
/// In order to use a GPIO as a slave select you must ignore and not
/// electrically attach anything to the slave select pin the SPIDEV
/// device uses as it will be asserted on each write.
///
/// In other words, the SPIDev device is needed to shift the data in
/// and out, however you must ignore its internal slave select line
/// entirely if you wish to use GPIO based slave selects. Otherwise
/// any device attached to it will be receive every write to the
/// SPIPort no matter which GPIO slave select is also asserted.
///
/// </summary>
/// <returns>ssHandle - the handle for the Slave Device or null for fail</returns>
/// <param name="spiSlaveDeviceIn">The GPIO of the pin we use as the slave select</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public SPISlaveDeviceHandle EnableSPIGPIOSlaveDevice(GpioEnum gpioEnum)
{
// get first slave device. We need to check we have one
SPISlaveDeviceHandle ssHandle = GetFirstSlaveDeviceWithFD();
// sanity check
if (ssHandle == null)
{
throw new Exception ("At least one non GPIO Slave Device must be enabled first.");
}
// create a new output port
OutputPortMM gpioSlaveSelect = new OutputPortMM(gpioEnum);
// set this high by default, most modes have slave selects high and go low to activate
gpioSlaveSelect.Write(true);
// create a new slave device handle
SPISlaveDeviceHandle outHandle = new SPISlaveDeviceHandle(SPISlaveDeviceEnum.SPI_SLAVEDEVICE_GPIO, gpioSlaveSelect);
if(outHandle == null)
{
throw new Exception("Could not create GPIO based slave select device");
}
//Console.WriteLine("SPIPort GPIO Slave Device Enabled: "+ gpioEnum.ToString());
// record that we opened this slave device (so we can close it later)
openSlaveDevices.Add(outHandle);
// return the slave device handle
return outHandle;
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Disables a SPI slave device.
/// </summary>
/// <param name="ssHandle">The SPI Slave Device handle to disable</param>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
private void DisableSPISlaveDevice(SPISlaveDeviceHandle ssHandle)
{
if (ssHandle == null) return;
// are we an internal chip select type slave device?
if ((ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS0) ||
(ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CS1))
{
// yes we are, close it this way
// does it have a valid file descriptor
if (ssHandle.SpiDevFileDescriptor < 0) return;
// do an external close
ExternalFileClose(ssHandle.SpiDevFileDescriptor);
// mark it as having been closed
ssHandle.Reset();
}
else if (ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_GPIO)
{
// yes we are, close it this way
// does it have a valid file descriptor
if (ssHandle.GpioSlaveSelect == null) return;
// close it
ssHandle.GpioSlaveSelect.ClosePort();
ssHandle.GpioSlaveSelect.Dispose();
ssHandle.GpioSlaveSelect = null;
// mark it as having been closed
ssHandle.Reset();
}
else
{
// unknown type of slave device should never happen
throw new Exception ("Unknown SPI Slave Device:" + ssHandle.SPISlaveDevice.ToString());
}
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Disables all SPI slave devices.
/// </summary>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
private void DisableAllSPISlaveDevices()
{
if (openSlaveDevices == null) return;
foreach (SPISlaveDeviceHandle ssHandle in openSlaveDevices)
{
// disable the device
DisableSPISlaveDevice(ssHandle);
}
// reset this
openSlaveDevices = new List<SPISlaveDeviceHandle>();
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Closes the port. Because we do not open the port at the PortFS level
/// we cannot close it there either. This overrides the PortFS.ClosePort()
/// and does what is necessary internally to close things up.
///
/// </summary>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public override void ClosePort()
{
//Console.WriteLine("SPIPort Closing");
DisableAllSPISlaveDevices();
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Gets the SPI Port. There is no Set accessor this is set in the constructor
/// </summary>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public SPIPortEnum SPIPort
{
get
{
return spiPort;
}
}
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Gets the PortDirection
/// </summary>
/// <history>
/// 21 Dec 14 Cynic - Originally written
/// </history>
public override PortDirectionEnum PortDirection()
{
return PortDirectionEnum.PORTDIR_INPUTOUTPUT;
}
// #########################################################################
// ### Dispose Code
// #########################################################################
#region
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
/// <summary>
/// Implement IDisposable.
/// Dispose(bool disposing) executes in two distinct scenarios.
///
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
///
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
///
/// see: http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28v=vs.110%29.aspx
///
/// </summary>
/// <history>
/// 28 Aug 14 Cynic - Originally written
/// </history>
protected override void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(Disposed==false)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing==true)
{
// Dispose managed resources.
}
// Call the appropriate methods to clean up
// unmanaged resources here. If disposing is false,
// only the following code is executed.
// Clean up our code
//Console.WriteLine("Disposing SPIPORT");
// call the base to dispose there
base.Dispose(disposing);
}
}
#endregion
// #########################################################################
// ### External Library Calls
// #########################################################################
#region External Library Calls
// these calls are in the libc.so.6 library. We can just say "libc" and mono
// will figure out which libc.so is the latest version and use that.
[DllImport("libc", EntryPoint = "ioctl")]
static extern int ExternalIoCtl(int fd, uint request, ref uint intVal);
[DllImport("libc", EntryPoint = "ioctl")]
static extern int ExternalIoCtl(int fd, uint request, ref spi_ioc_transfer xfer);
[DllImport("libc", EntryPoint = "open")]
static extern int ExternalFileOpen(string path, int flags);
[DllImport("libc", EntryPoint = "close")]
static extern int ExternalFileClose(int fd);
#endregion
}
}