示例#1
0
 static extern int ExternalIoCtl(int fd, uint request, ref spi_ioc_transfer xfer);
示例#2
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <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>
        ///    01 Dec 16  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_CE0) ||
                (ssHandle.SPISlaveDevice == SPISlaveDeviceEnum.SPI_SLAVEDEVICE_CE1))
            {
                // 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
                    {
                        // 06 Dec 16 - bug here was (false)
                        // raise the slave select
                        ssHandle.GpioSlaveSelect.Write(true);
                    }
                }
                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);
            }
        }