//============================================================================
//Copyright © 2012, open source hardware engineering
// 
//This application is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 3 of the License, or (at your option) any later version.
//
//This application is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR When PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, see <http://www.gnu.org/licenses/>
//
//=============================================================================
#ifndef WxSpi_h
#define WxSpi_h

#include "Arduino.h"

#define SPI_END   0x0100
#define SPI_LAST  0x0200
//
// Provides synchronous and asynchronous operation of the SPI interface
// in master mode only.
//
class WxSpiInterface
{
public:
  WxSpiInterface();
  
  //
  // sets the SPI clock rate to a value that is less than or equal to
  // the requested rate in Hz -- if possible.
  //
  // spi_mode is 0,1,2 or 3 and determines the clock polarity and 
  // clock edge on which data is sampled. the mode values adhere to
  // the industry-standard definition.
  //
  // if begin() is not called prior to using the other methods,
  // the spi interface will not work correctly. begin() can be called
  // again later to change clock rate or mode settings -- but don't 
  // call it while spi_busy() returns true.
  //
  void declare_slave_pin(byte pin);
  //
  // prepares the SPI interface for use in master mode.
  //
  // clock_rate is a requested SPI clock rate in Hz. the actual
  // clock rate will be set equal to or less than the requested
  // rate, if possible.
  //
  // mode is the desired SPI mode -- according to industry standard
  // definition which specifies the clock polarity and clock edge
  // on which data is sampled. Valid values are 0,1,2,3
  //
  // Returns the selected clock rate in Hz, which will not
  // in general be equal to the requested clock rate.
  //
  unsigned long begin(unsigned long clock_rate, byte mode);
  //
  // Before initiating an SPI transaction, choose the slave with this
  // method. If there is only one slave it is not necessary to use
  // this -- the slave was set when declare_slave_pin() was called.
  // The last slave selected is remembered, so this method is only 
  // required when a different slave select pin is desired.
  //
  // *** DO NOT call this method if busy() == true !!!
  //
  void select_slave(byte pin);
  //
  // methods for asynchronous access. These allow the loop() function
  // to do other tasks while the SPI I/O is in process.
  //
  // if busy() is true, the SPI interface is busy with a transaction.
  // do not call begin_write(), read_count() or read() while busy() == true
  // when false, busy() will not change state unless the begin_write() or write_read()
  // methods are called. while true, busy() can change to false at any time asynchronously.
  //
  boolean busy(); 
  //
  // only valid when not busy. if the transmit buffer was too long this will be true
  //
  boolean overflow();
  int flip_count();
  //
  // initiates transmission of a sequence of one or more commands to the
  // slave last selected with select_slave().
  //
  boolean begin_write(const unsigned int *commands);
  //
  // causes transmission of any commands in process to be aborted.
  // busy will not go false however until any byte that is in the process
  // of being sent by the hardware is finished. the abort is not complete
  // until busy() == false.
  //
  void abort();
  //
  // valid when busy() == false. returns number of bytes available in 
  // the input buffer. 
  //
  byte read_count();
  //
  // when busy() == false, this is used to retrieve the data received
  // during the last SPI transaction. If multiple commands were sent,
  // then multiple responses will be present in the buffer.
  //
  boolean read(byte *buffer, byte buffer_length);
  //
  // methods for synchronous access
  //
  // write_read() performs and entire SPI transaction (or transactions),
  // and will busy-wait while the I/O is occuring.
  //
  boolean write_read(const unsigned int *commands, byte *replies, byte max_reply_length);
  //
  // after starting an asynchronous operation with begin_write(), this method
  // can be used to complete the transaction -- it will busy-wait as necessary
  // until the transaction has completed.
  //
  boolean read_wait(byte *replies, byte max_reply_length);
  //
  // abort_wait() will abort any currently active transaction, and 
  // busy-wait until the abort process is complete
  //
  void abort_wait();

private:
  // this is the currently chosen slave select pin.
  byte slave_pin;
};

extern WxSpiInterface WxSpi;

#endif
