/*----------------------------------------------------------------------------*/
/* 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.  */
/*----------------------------------------------------------------------------*/

#ifndef __SPI_H__
#define __SPI_H__

#include "ChipObject.h"
#include "SensorBase.h"

class DigitalOutput;
class DigitalInput;

/**
 * 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.
 *
 * The FPGA only supports a single SPI interface.
 */
class SPI : public SensorBase
{
public:
	enum tFrameMode {kChipSelect, kPreLatchPulse, kPostLatchPulse, kPreAndPostLatchPulse};
	enum tSPIConstants {kReceiveFIFODepth=512, kTransmitFIFODepth=512};

	SPI(DigitalOutput &clk, DigitalOutput &mosi, DigitalInput &miso);
	SPI(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso);
	SPI(DigitalOutput &clk, DigitalOutput &mosi);
	SPI(DigitalOutput *clk, DigitalOutput *mosi);
	SPI(DigitalOutput &clk, DigitalInput &miso);
	SPI(DigitalOutput *clk, DigitalInput *miso);
	virtual ~SPI();

	void SetBitsPerWord(UINT32 bits);
	UINT32 GetBitsPerWord();
	void SetClockRate(double hz);

	void SetMSBFirst();
	void SetLSBFirst();

	void SetSampleDataOnFalling();
	void SetSampleDataOnRising();

	void SetSlaveSelect(DigitalOutput *ss, tFrameMode mode=kChipSelect, bool activeLow=false);
	void SetSlaveSelect(DigitalOutput &ss, tFrameMode mode=kChipSelect, bool activeLow=false);
	DigitalOutput *GetSlaveSelect(tFrameMode *mode=NULL, bool *activeLow=NULL);

	void SetClockActiveLow();
	void SetClockActiveHigh();

	virtual void ApplyConfig();

	virtual UINT16 GetOutputFIFOAvailable();
	virtual UINT16 GetNumReceived();

	virtual bool IsDone();
	bool HadReceiveOverflow();

	virtual void Write(UINT32 data);
	virtual UINT32 Read(bool initiate = false);

	virtual void Reset();
	virtual void ClearReceivedData();

protected:
	static SEM_ID m_semaphore;

	tSPI* m_spi;
	tSPI::tConfig m_config;
	tSPI::tChannels m_channels;
	DigitalOutput *m_ss;

private:
	void Init(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso);

	DISALLOW_COPY_AND_ASSIGN(SPI);
};

#endif
