This is the latest WPILib src, VisionSample2013, cRIO image, ... pulled down from firstforge.wpi.edu.
There might be risks in using the top of tree rather than an official release, but the commit messages do mention fixes for some deadlocks and race conditions.
git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4066 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/azaleasource/WPILibCProgramming/trunk/WPILib/SPI.cpp b/azaleasource/WPILibCProgramming/trunk/WPILib/SPI.cpp
new file mode 100644
index 0000000..722c07dc
--- /dev/null
+++ b/azaleasource/WPILibCProgramming/trunk/WPILib/SPI.cpp
@@ -0,0 +1,528 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+
+#include "SPI.h"
+
+#include "ChipObject/tSPI.h"
+#include "DigitalInput.h"
+#include "DigitalOutput.h"
+#include "NetworkCommunication/UsageReporting.h"
+#include "Synchronized.h"
+#include "WPIErrors.h"
+
+#include <math.h>
+#include <usrLib.h>
+
+SEM_ID SPI::m_semaphore = NULL;
+
+/**
+ * Constructor for input and output.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param mosi The digital output for the written data to the slave
+ * (master-out slave-in).
+ * @param miso The digital input for the input data from the slave
+ * (master-in slave-out).
+ */
+SPI::SPI(DigitalOutput &clk, DigitalOutput &mosi, DigitalInput &miso)
+{
+ Init(&clk, &mosi, &miso);
+}
+
+/**
+ * Constructor for input and output.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param mosi The digital output for the written data to the slave
+ * (master-out slave-in).
+ * @param miso The digital input for the input data from the slave
+ * (master-in slave-out).
+ */
+SPI::SPI(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso)
+{
+ Init(clk, mosi, miso);
+}
+
+/**
+ * Constructor for output only.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param mosi The digital output for the written data to the slave
+ * (master-out slave-in).
+ */
+SPI::SPI(DigitalOutput &clk, DigitalOutput &mosi)
+{
+ Init(&clk, &mosi, NULL);
+}
+
+/**
+ * Constructor for output only.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param mosi The digital output for the written data to the slave
+ * (master-out slave-in).
+ */
+SPI::SPI(DigitalOutput *clk, DigitalOutput *mosi)
+{
+ Init(clk, mosi, NULL);
+}
+
+/**
+ * Constructor for input only.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param miso The digital input for the input data from the slave
+ * (master-in slave-out).
+ */
+SPI::SPI(DigitalOutput &clk, DigitalInput &miso)
+{
+ Init(&clk, NULL, &miso);
+}
+
+/**
+ * Constructor for input only.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param miso The digital input for the input data from the slave
+ * (master-in slave-out).
+ */
+SPI::SPI(DigitalOutput *clk, DigitalInput *miso)
+{
+ Init(clk, NULL, miso);
+}
+
+/**
+ * Destructor.
+ */
+SPI::~SPI()
+{
+ delete m_spi;
+}
+
+/**
+ * Initialize SPI channel configuration.
+ *
+ * @param clk The digital output for the clock signal.
+ * @param mosi The digital output for the written data to the slave
+ * (master-out slave-in).
+ * @param miso The digital input for the input data from the slave
+ * (master-in slave-out).
+ */
+void SPI::Init(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso)
+{
+ if (m_semaphore == NULL)
+ {
+ m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
+ }
+
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ m_spi = tSPI::create(&localStatus);
+ wpi_setError(localStatus);
+
+ m_config.BusBitWidth = 8;
+ m_config.ClockHalfPeriodDelay = 0;
+ m_config.MSBfirst = 0;
+ m_config.DataOnFalling = 0;
+ m_config.LatchFirst = 0;
+ m_config.LatchLast = 0;
+ m_config.FramePolarity = 0;
+ m_config.WriteOnly = miso ? 0 : 1;
+ m_config.ClockPolarity = 0;
+
+ m_channels.SCLK_Channel = clk->GetChannelForRouting();
+ m_channels.SCLK_Module = clk->GetModuleForRouting();
+ m_channels.SS_Channel = 0;
+ m_channels.SS_Module = 0;
+
+ if (mosi)
+ {
+ m_channels.MOSI_Channel = mosi->GetChannelForRouting();
+ m_channels.MOSI_Module = mosi->GetModuleForRouting();
+ }
+ else
+ {
+ m_channels.MOSI_Channel = 0;
+ m_channels.MOSI_Module = 0;
+ }
+
+ if (miso)
+ {
+ m_channels.MISO_Channel = miso->GetChannelForRouting();
+ m_channels.MISO_Module = miso->GetModuleForRouting();
+ }
+ else
+ {
+ m_channels.MISO_Channel = 0;
+ m_channels.MISO_Module = 0;
+ }
+
+ m_ss = NULL;
+
+ static INT32 instances = 0;
+ instances++;
+ nUsageReporting::report(nUsageReporting::kResourceType_SPI, instances);
+}
+
+/**
+ * Configure the number of bits from each word that the slave transmits
+ * or receives.
+ *
+ * @param bits The number of bits in one frame (1 to 32 bits).
+ */
+void SPI::SetBitsPerWord(UINT32 bits)
+{
+ m_config.BusBitWidth = bits;
+}
+
+/**
+ * Get the number of bits from each word that the slave transmits
+ * or receives.
+ *
+ * @return The number of bits in one frame (1 to 32 bits).
+ */
+UINT32 SPI::GetBitsPerWord()
+{
+ return m_config.BusBitWidth;
+}
+
+/**
+ * Configure the rate of the generated clock signal.
+ * The default and maximum value is 76,628.4 Hz.
+ *
+ * @param hz The clock rate in Hertz.
+ */
+void SPI::SetClockRate(double hz)
+{
+ int delay = 0;
+ // TODO: compute the appropriate values based on digital loop timing
+ if (hz <= 76628.4)
+ {
+ double v = (1.0/hz)/1.305e-5;
+ int intv = (int)v;
+ if (v-intv > 0.5)
+ delay = intv;
+ else
+ delay = intv-1;
+ }
+ if (delay > 255)
+ {
+ wpi_setWPIError(SPIClockRateTooLow);
+ delay = 255;
+ }
+ m_config.ClockHalfPeriodDelay = delay;
+}
+
+/**
+ * Configure the order that bits are sent and received on the wire
+ * to be most significant bit first.
+ */
+void SPI::SetMSBFirst()
+{
+ m_config.MSBfirst = 1;
+}
+
+/**
+ * Configure the order that bits are sent and received on the wire
+ * to be least significant bit first.
+ */
+void SPI::SetLSBFirst()
+{
+ m_config.MSBfirst = 0;
+}
+
+/**
+ * Configure that the data is stable on the falling edge and the data
+ * changes on the rising edge.
+ */
+void SPI::SetSampleDataOnFalling()
+{
+ m_config.DataOnFalling = 1;
+}
+
+/**
+ * Configure that the data is stable on the rising edge and the data
+ * changes on the falling edge.
+ */
+void SPI::SetSampleDataOnRising()
+{
+ m_config.DataOnFalling = 0;
+}
+
+/**
+ * Configure the slave select line behavior.
+ *
+ * @param ss slave select digital output.
+ * @param mode Frame mode:
+ * kChipSelect: active for the duration of the frame.
+ * kPreLatchPulse: pulses before the transfer of each frame.
+ * kPostLatchPulse: pulses after the transfer of each frame.
+ * kPreAndPostLatchPulse: pulses before and after each frame.
+ * @param activeLow True if slave select line is active low.
+ */
+void SPI::SetSlaveSelect(DigitalOutput *ss, tFrameMode mode, bool activeLow)
+{
+ if (ss)
+ {
+ m_channels.SS_Channel = ss->GetChannelForRouting();
+ m_channels.SS_Module = ss->GetModuleForRouting();
+ }
+ else
+ {
+ m_channels.SS_Channel = 0;
+ m_channels.SS_Module = 0;
+ }
+ m_ss = ss;
+
+ switch (mode)
+ {
+ case kChipSelect:
+ m_config.LatchFirst = 0;
+ m_config.LatchLast = 0;
+ break;
+ case kPreLatchPulse:
+ m_config.LatchFirst = 1;
+ m_config.LatchLast = 0;
+ break;
+ case kPostLatchPulse:
+ m_config.LatchFirst = 0;
+ m_config.LatchLast = 1;
+ break;
+ case kPreAndPostLatchPulse:
+ m_config.LatchFirst = 1;
+ m_config.LatchLast = 1;
+ break;
+ }
+
+ m_config.FramePolarity = activeLow ? 1 : 0;
+}
+
+/**
+ * Configure the slave select line behavior.
+ *
+ * @param ss slave select digital output.
+ * @param mode Frame mode:
+ * kChipSelect: active for the duration of the frame.
+ * kPreLatchPulse: pulses before the transfer of each frame.
+ * kPostLatchPulse: pulses after the transfer of each frame.
+ * kPreAndPostLatchPulse: pulses before and after each frame.
+ * @param activeLow True if slave select line is active low.
+ */
+void SPI::SetSlaveSelect(DigitalOutput &ss, tFrameMode mode, bool activeLow)
+{
+ SetSlaveSelect(&ss, mode, activeLow);
+}
+
+/**
+ * Get the slave select line behavior.
+ *
+ * @param mode Frame mode:
+ * kChipSelect: active for the duration of the frame.
+ * kPreLatchPulse: pulses before the transfer of each frame.
+ * kPostLatchPulse: pulses after the transfer of each frame.
+ * kPreAndPostLatchPulse: pulses before and after each frame.
+ * @param activeLow True if slave select line is active low.
+ * @return The slave select digital output.
+ */
+DigitalOutput *SPI::GetSlaveSelect(tFrameMode *mode, bool *activeLow)
+{
+ if (mode != NULL)
+ {
+ *mode = (tFrameMode) (m_config.LatchFirst | (m_config.LatchLast << 1));
+ }
+ if (activeLow != NULL)
+ {
+ *activeLow = m_config.FramePolarity != 0;
+ }
+ return m_ss;
+}
+
+/**
+ * Configure the clock output line to be active low.
+ * This is sometimes called clock polarity high.
+ */
+void SPI::SetClockActiveLow()
+{
+ m_config.ClockPolarity = 1;
+}
+
+/**
+ * Configure the clock output line to be active high.
+ * This is sometimes called clock polarity low.
+ */
+void SPI::SetClockActiveHigh()
+{
+ m_config.ClockPolarity = 0;
+}
+
+/**
+ * Apply configuration settings and reset the SPI logic.
+ */
+void SPI::ApplyConfig()
+{
+ Synchronized sync(m_semaphore);
+
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ m_spi->writeConfig(m_config, &localStatus);
+ m_spi->writeChannels(m_channels, &localStatus);
+ m_spi->strobeReset(&localStatus);
+ wpi_setError(localStatus);
+}
+
+/**
+ * Get the number of words that can currently be stored before being
+ * transmitted to the device.
+ *
+ * @return The number of words available to be written.
+ */
+UINT16 SPI::GetOutputFIFOAvailable()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ UINT16 result = m_spi->readAvailableToLoad(&localStatus);
+ wpi_setError(localStatus);
+ return result;
+}
+
+/**
+ * Get the number of words received and currently available to be read from
+ * the receive FIFO.
+ *
+ * @return The number of words available to read.
+ */
+UINT16 SPI::GetNumReceived()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ UINT16 result = m_spi->readReceivedElements(&localStatus);
+ wpi_setError(localStatus);
+ return result;
+}
+
+/**
+ * Have all pending transfers completed?
+ *
+ * @return True if no transfers are pending.
+ */
+bool SPI::IsDone()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ bool result = m_spi->readStatus_Idle(&localStatus);
+ wpi_setError(localStatus);
+ return result;
+}
+
+/**
+ * Determine if the receive FIFO was full when attempting to add new data at
+ * end of a transfer.
+ *
+ * @return True if the receive FIFO overflowed.
+ */
+bool SPI::HadReceiveOverflow()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ bool result = m_spi->readStatus_ReceivedDataOverflow(&localStatus);
+ wpi_setError(localStatus);
+ return result;
+}
+
+/**
+ * Write a word to the slave device. Blocks until there is space in the
+ * output FIFO.
+ *
+ * If not running in output only mode, also saves the data received
+ * on the MISO input during the transfer into the receive FIFO.
+ */
+void SPI::Write(UINT32 data)
+{
+ if (m_channels.MOSI_Channel == 0 && m_channels.MOSI_Module == 0)
+ {
+ wpi_setWPIError(SPIWriteNoMOSI);
+ return;
+ }
+
+ Synchronized sync(m_semaphore);
+
+ while (GetOutputFIFOAvailable() == 0)
+ taskDelay(NO_WAIT);
+
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ m_spi->writeDataToLoad(data, &localStatus);
+ m_spi->strobeLoad(&localStatus);
+ wpi_setError(localStatus);
+}
+
+/**
+ * Read a word from the receive FIFO.
+ *
+ * Waits for the current transfer to complete if the receive FIFO is empty.
+ *
+ * If the receive FIFO is empty, there is no active transfer, and initiate
+ * is false, errors.
+ *
+ * @param initiate If true, this function pushes "0" into the
+ * transmit buffer and initiates a transfer.
+ * If false, this function assumes that data is
+ * already in the receive FIFO from a previous write.
+ */
+UINT32 SPI::Read(bool initiate)
+{
+ if (m_channels.MISO_Channel == 0 && m_channels.MISO_Module == 0)
+ {
+ wpi_setWPIError(SPIReadNoMISO);
+ return 0;
+ }
+
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ UINT32 data;
+ {
+ Synchronized sync(m_semaphore);
+
+ if (initiate)
+ {
+ m_spi->writeDataToLoad(0, &localStatus);
+ m_spi->strobeLoad(&localStatus);
+ }
+
+ // Do we have anything ready to read?
+ if (GetNumReceived() == 0)
+ {
+ if (!initiate && IsDone() && GetOutputFIFOAvailable() == kTransmitFIFODepth)
+ {
+ // Nothing to read: error out
+ wpi_setWPIError(SPIReadNoData);
+ return 0;
+ }
+
+ // Wait for the transaction to complete
+ while (GetNumReceived() == 0)
+ taskDelay(NO_WAIT);
+ }
+
+ m_spi->strobeReadReceivedData(&localStatus);
+ data = m_spi->readReceivedData(&localStatus);
+ }
+ wpi_setError(localStatus);
+
+ return data;
+}
+
+/**
+ * Stop any transfer in progress and empty the transmit FIFO.
+ */
+void SPI::Reset()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ m_spi->strobeReset(&localStatus);
+ wpi_setError(localStatus);
+}
+
+/**
+ * Empty the receive FIFO.
+ */
+void SPI::ClearReceivedData()
+{
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ m_spi->strobeClearReceivedData(&localStatus);
+ wpi_setError(localStatus);
+}