blob: 64215354d4131228731e2a2977b6ae131b1281a6 [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. 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 the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <hal/SPITypes.h>
#include <wpi/deprecated.h>
#include <wpi/span.h>
#include "absl/types/span.h"
#include <cstdint>
#include <memory>
namespace frc {
class DigitalSource;
/**
* SPI bus interface class.
*
* This class is intended to be used by sensor (and other SPI device) drivers.
* It probably should not be used directly.
*
*/
class SPI final {
public:
enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
/**
* Constructor
*
* @param port the physical SPI port
*/
explicit SPI(Port port);
~SPI();
SPI(SPI &&) = default;
SPI &operator=(SPI &&) = default;
/**
* Configure the rate of the generated clock signal.
*
* The default value is 500,000Hz.
* The maximum value is 4,000,000Hz.
*
* @param hz The clock rate in Hertz.
*/
void SetClockRate(int hz);
/**
* Configure the order that bits are sent and received on the wire
* to be most significant bit first.
*/
void SetMSBFirst();
/**
* Configure the order that bits are sent and received on the wire
* to be least significant bit first.
*/
void SetLSBFirst();
/**
* Configure that the data is stable on the leading edge and the data
* changes on the trailing edge.
*/
void SetSampleDataOnLeadingEdge();
/**
* Configure that the data is stable on the trailing edge and the data
* changes on the leading edge.
*/
void SetSampleDataOnTrailingEdge();
/**
* Configure that the data is stable on the falling edge and the data
* changes on the rising edge.
*/
WPI_DEPRECATED("Use SetSampleDataOnTrailingEdge in most cases.")
void SetSampleDataOnFalling();
/**
* Configure that the data is stable on the rising edge and the data
* changes on the falling edge.
*/
WPI_DEPRECATED("Use SetSampleDataOnLeadingEdge in most cases")
void SetSampleDataOnRising();
/**
* Configure the clock output line to be active low.
* This is sometimes called clock polarity high or clock idle high.
*/
void SetClockActiveLow();
/**
* Configure the clock output line to be active high.
* This is sometimes called clock polarity low or clock idle low.
*/
void SetClockActiveHigh();
/**
* Configure the chip select line to be active high.
*/
void SetChipSelectActiveHigh();
/**
* Configure the chip select line to be active low.
*/
void SetChipSelectActiveLow();
/**
* Write data 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.
*/
virtual int Write(uint8_t *data, int size);
/**
* 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.
*/
virtual int Read(bool initiate, uint8_t *dataReceived, int size);
/**
* Perform a simultaneous read/write transaction with the device
*
* @param dataToSend The data to be written out to the device
* @param dataReceived Buffer to receive data from the device
* @param size The length of the transaction, in bytes
*/
virtual int Transaction(uint8_t *dataToSend, uint8_t *dataReceived, int size);
/**
* Initialize automatic SPI transfer engine.
*
* Only a single engine is available, and use of it blocks use of all other
* chip select usage on the same physical SPI port while it is running.
*
* @param bufferSize buffer size in bytes
*/
void InitAuto(int bufferSize);
/**
* Frees the automatic SPI transfer engine.
*/
void FreeAuto();
/**
* Set the data to be transmitted by the engine.
*
* Up to 16 bytes are configurable, and may be followed by up to 127 zero
* bytes.
*
* @param dataToSend data to send (maximum 16 bytes)
* @param zeroSize number of zeros to send after the data
*/
void SetAutoTransmitData(absl::Span<const uint8_t> dataToSend, int zeroSize);
/**
* Start running the automatic SPI transfer engine at a periodic rate.
*
* InitAuto() and SetAutoTransmitData() must be called before calling this
* function.
*
* @param period period between transfers, in seconds (us resolution)
*/
void StartAutoRate(double period);
/**
* Start running the automatic SPI transfer engine when a trigger occurs.
*
* InitAuto() and SetAutoTransmitData() must be called before calling this
* function.
*
* @param source digital source for the trigger (may be an analog trigger)
* @param rising trigger on the rising edge
* @param falling trigger on the falling edge
*/
void StartAutoTrigger(DigitalSource &source, bool rising, bool falling);
/**
* Stop running the automatic SPI transfer engine.
*/
void StopAuto();
/**
* Force the engine to make a single transfer.
*/
void ForceAutoRead();
/**
* Read data that has been transferred by the automatic SPI transfer engine.
*
* Transfers may be made a byte at a time, so it's necessary for the caller
* to handle cases where an entire transfer has not been completed.
*
* Each received data sequence consists of a timestamp followed by the
* received data bytes, one byte per word (in the least significant byte).
* The length of each received data sequence is the same as the combined
* size of the data and zeroSize set in SetAutoTransmitData().
*
* Blocks until numToRead words have been read or timeout expires.
* May be called with numToRead=0 to retrieve how many words are available.
*
* @param buffer buffer where read words are stored
* @param numToRead number of words to read
* @param timeout timeout in seconds (ms resolution)
* @return Number of words remaining to be read
*/
int ReadAutoReceivedData(uint32_t *buffer, int numToRead, double timeout);
/**
* Get the number of bytes dropped by the automatic SPI transfer engine due
* to the receive buffer being full.
*
* @return Number of bytes dropped
*/
int GetAutoDroppedCount();
/**
* Configure the Auto SPI Stall time between reads.
*
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
* MXP.
* @param csToSclkTicks the number of ticks to wait before asserting the cs
* pin
* @param stallTicks the number of ticks to stall for
* @param pow2BytesPerRead the number of bytes to read before stalling
*/
void ConfigureAutoStall(int csToSclkTicks, int stallTicks,
int pow2BytesPerRead);
protected:
hal::SPIPort m_port;
bool m_msbFirst = false; // Default little-endian
bool m_sampleOnTrailing = false; // Default data updated on falling edge
bool m_clockIdleHigh = false; // Default clock active high
private:
void Init();
};
} // namespace frc