/*                                             -*- mode:C++; fill-column:100 -*-
  SFBSDRaw.h - Bit-banged SDCard raw disk access.
  Copyright (C) 2010 The Regents of the University of New Mexico
 
  This library 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 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
 */

/**
  \file SFBSDRaw.h Bit-banged SDCard raw disk access.  
  \author David H. Ackley.  
  \date (C) 2010 All rights reserved.
  \lgpl
  \since 0.9.17
 */
#ifndef SFBSDRAW_H
#define SFBSDRAW_H

#include "SFBTypes.h"           // For u32 etc
#include "SFBConstants.h"       // For FACE_COUNT

#define SDRAW_BLOCK_SIZE_BIT_COUNT 9
#define SDRAW_BLOCK_SIZE (1<<(SDRAW_BLOCK_SIZE_BIT_COUNT)) // 512 bytes per block
#define SDRAW_BLOCK_SIZE_BIT_MASK ((SDRAW_BLOCK_SIZE)-1)

/**
   Information associated with an SD Card.  Read via SDRaw::getInfo().  Writing not currently
   supported.
 */
struct SDRawDiskInfo {
  u32 serialNumber;             ///< Card serial number
  u32 blockCount;               ///< Number of 512 byte blocks in the disk
  u8 manufacturer;              ///< Manufacturer code, e.g., 2==SanDisk
  u8 oem[2+1];                  ///< Two byte ASCII OEM code, plus courtesy null 
  u8 product[5+1];              ///< Five bytes ASCII product code, plus courtesy null
  u8 revision;                  ///< Product revision, as two BCD digits (e.g., 0x32==3.2)
  u8 year;                      ///< Year of manufacture (0 means year 2000)
  u8 month;                     ///< Month of manufacture (1 means January)
  u8 format;                    ///< File format code.  Unreliable.  One-time writable.
  bool copy;                    ///< Contents is original (0) or a copy (1).  One-time writable.
  bool writeProtect;            ///< Entire card is permanently write-protected if 1.  One-time writable.
  bool writeProtectTemporary;   ///< Entire card is currently write-protected if 1.  Rewritable.
};

/**
   A class to control an SD Card.

   Capable of reading and writing (at least some) SD and SDHC cards on any face at rates from
   10KBytes/sec to 100Kbytes/sec or more, depending on factors such as the card type, size, and
   manufacturer, processor clock speed and load, programming technique, and the alignment of Jupiter
   with Mars.  Getting 40-50KB/sec read and write is fairly easy; 120KB/sec read and write, or even
   more, can sometimes be achieved in benchmark code.

   Note this code provides \e NO \e FILE \e SYSTEM!  This is low-level direct disk access in terms
   of 512-byte blocks from the beginning of the disk to the end.  And there is \e nothing stopping
   your sketch from creaming whatever file system might already be on the card, except your sketch
   not doing disk writes!

   Using the simplest #begin(u8) interface, this code is designed to drive an 'IXM SD Cell' board
   containing a MicroSD card, connected by at least one 7 pin header, on the LED side of the IXM,
   but the code can be configured (via #begin(u8,u8,u8,u8,u8)) to drive an SD card (in SPI mode) via
   any four pins (data or Tx or Rx) and a single face power connection (so that the card can be
   power-cycled as part of its initialization sequence).

   <b>Warning: <i>Misplugging</i> an IXM SD Cell to an IXM while it contains an SD Card can
   <i>INSTANTLY KILL</i> the SD Card when the IXM is powered up!  Always 'pop' the card before
   plugging or unplugging or handling the board!  And be CAREFUL what you touch \e while you're
   pushing and popping cards!</b>

   Cards that have been tested successfully include: <ol>

   <li>SanDisk 2GB MicroSD card, product code SU02G manufactured 11/2009: Up to approximately
       140KB/sec block read speed, up to approximately 120KB/sec block write speed.  I've apparently
       killed multiple of these through misplugging or static discharge or something (thus the
       warning above) -- with the most common symptom being that the cards init successfully but
       then fail during the first read or write operation .</li>

   <li>SanDisk 4GB MicroSDHC card, product code SU04G manufactured 2/2010: Current workhorse (as of
       4/10; under $15 at WalMart).  Up to approximately 140KB/sec block read speed, up to
       approximately 150KB/sec block write speed (yes, it benched faster writing than reading..  No
       idea why.).</li>

   <li>PNY 4GB MicroSDHC card, product code SA04G manufactured 12/2009: Cheap, up to approximately
       140KB/sec block read speed, up to approximately 60KB/sec block write speed.</li>

   </ol>

   Note that all speed numbers mentioned are only crude estimates, based on highly-variable
   statistically-insignificant timings on stripped-down benchmarking code!  Expect less, perhaps \e
   much less, from actual production code!  In particular, doing byte-at-a-time access, rather than
   dealing with full blocks, can easily halve those numbers, or worse.

   \e Your \e Mileage \e Will \e Vary!

   Note also that this library currently supports only single-block-at-a-time transfers; perhaps
   that is a factor in the PNY's write performance.

 */
class SDRaw {
public:
  /**
     State codes of an SDRaw host controller.
   */
  enum State { 
    NOT_BEGUN=0,                ///< No #begin() called (since last #end(), at any rate)
    UNINITTED,                  ///< #begin() called but not yet #init()
    RESET_FAILED,               ///< #init() couldn't reset the card -- a common result when no card is present
    CRC_ON_FAILED,              ///< Attempt to enable CRC checking failed during #init().  This is a bad sign.
    TYPE_CHECK_FAILED,          ///< Determining SD controller version failed during #init().  Another bad sign.
    OP_COND_FAILED,             ///< Attempt to boot the SD card failed during #init().  Yet another bad sign.
    READ_OCR_FAILED,            ///< Checking for an SDHC card failed during #init().  Also a bad sign. 
    CONFIG_FAILED,              ///< Attempt to set the block size failed during #init().  Yes, another bad sign.
    ACTIVE,                     ///< #init() completed successfully, card ready for read/write.
    INACTIVE_READ,              ///< #read(u64,u8*,u32) called when not #ACTIVE.  This means a sketch bug.
    INACTIVE_WRITE,             ///< #write(u64,const u8*,u32) called when not #ACTIVE.  This means a sketch bug.
    ERROR_READ_SINGLE_BLOCK,    ///< Performing a block read failed.  May suggest a bad connection or card.
    ERROR_READ_REGISTER,        ///< Reading a card register failed.  May suggest a bad connection or card.
    ERROR_READ_TIMEOUT_DATA,    ///< Timeout reading a block or register.  May suggest a bad connection or card.
    ERROR_READ_CRC_DATA,        ///< Checksum mismatch on read data block.  May suggest a bad connection.
    ERROR_BAD_CSD_VERSION,      ///< Unrecognized version of CSD.  A bad sign, or a SD card from the future.
    ERROR_WRITE_TIMEOUT_DATA,   ///< Timeout writing a block.  May suggest a bad connection or card.
    ERROR_WRITE_SINGLE_BLOCK    ///< Performing a block write failed.  May suggest a bad connection or card.
  };

  /**
     Begin using an SDRaw object to control an SD card connected to \a face.  This is the simpler
     method, see #begin(u8,u8,u8,u8,u8) for the more general mechanism.  Note that the method only
     configures the SDRaw object; it still must be successfully initialized via #init() before it
     can be used to perform I/O.

     \param face A face connected -- in an IXM SD Cell-compatible fashion -- to a (micro) SD card.
   */
  void begin(u8 face) ;

  /**
     Begin using an SDRaw object to control an SD card.  The power to the SD card should be supplied
     by \a face, so that switching off and on the outbound power on that \a face will power-cycle
     the card.  In addition, four pins must be provided for the SPI-mode interface to the card.
     These pins may be any of the data or serial pins on the IXM, not necessarily just those on \a
     face.

     Note that the method only configures the SDRaw object; it still must be
     successfully initialized via #init() before it can be used to perform I/O.

     \param face A face whose outbound power is connected to a (micro) SD card.
     \param CSPin A pin connected to the Chip Select input of an SD card (in SPI mode)
     \param clkPin A pin connected to the Clock input of an SD card (in SPI mode)
     \param MOSIPin A pin connected to the Master-Out-Slave-In input of an SD card (in SPI mode)
     \param MISOPin A pin connected to the Master-In-Slave-Out output of an SD card (in SPI mode)
   */
  void begin(u8 face, u8 CSPin, u8 clkPin, u8 MOSIpin, u8 MISOpin) ;

  /**
     Deconfigure an SDRaw object.  Marks the SDRaw object internally as #NOT_BEGUN, but note this
     method does \e not undo the effects of a #begin() call.  In particular, pin functions and pin
     modes changed by a #begin() call \e remain changed.  It is the caller's responsibility to
     reconfigure any affected hardware as desired after this call.
   */
  bool end() ;

  /**
     Get the current #State of this SDRaw object.
   */
  u32 getState() { return status; }

  /**
     Return the total capacity of the SD card, measured in 512 byte blocks.  Returns 0 if the
     information cannot be accessed (because the SDRaw is not in state #ACTIVE, or some other
     error).
   */
  u32 getBlockCount() { return isActive() ? blockCapacity : 0; }

  /**
     Return the total capacity of the SD card, measured in bytes.  Returns 0 if the information
     cannot be accessed (because the SDRaw is not in state #ACTIVE, or some other error).
   */
  u64 getByteCount() { return ((u64) getBlockCount())<<SDRAW_BLOCK_SIZE_BIT_COUNT; }

  /**
     Return the face this SDRaw object is controlling to power the SD Card.  Returns garbage if
     #begin() has not yet been called.
   */
  u8 getFace() { return sdFace; }

  /**
     Attempt to initialize the SD card controlled by this SDRaw object.  Returns \c true if the
     initialization succeeds (and the card is then ready for I/O), and returns \c false if some
     error occurred during initialization (and then the card is not ready for I/O, but #getState()
     will provide more information about the error.

     Note that this method can take a \e long time to complete -- up to a second or perhaps even
     more -- regardless of whether it ultimately succeeds or fails.

     \returns \c true if initialization succeeded, \c false if an error occurred.
   */
  bool init() ;

  /** Return \c true iff this SDRaw object is prepared to perform a read or write operation. 
   */
  bool isActive() { return getState()==ACTIVE; }

  /**
     Read disk capacity and identification information from the disk.  If successful, returns \c
     true and populates the fields of \a info with the results.  Otherwise returns \c false (and
     #getState() should provide more information).

     \param info An #SDRawDiskInfo structure to populate.
   */
  bool getInfo(SDRawDiskInfo & info) ;

  /**
     Provide (or remove) a block-sized (512 bytes) buffer for the SDRaw object to use for data
     buffering.  It is not \e required to provide such a buffer, but if you don't then all your
     write operations must work in terms of 512 byte units at multiple-of-512 addresses, and all
     your read operations will involve reading at least 512 bytes from the disk, no matter what
     length your request.

     Note that if, and as long as, a \a buffer \e is provided for an #SDRaw to use, then the sketch
     should make no assumptions about the contents of that \a buffer at any given time.  In
     particular, the sketch should not assume that the \a buffer contains the most-recently read or
     written disk block, because the #SDRaw library is free to use the provided buffer for whatever
     internal purposes it wishes.

     \param buffer      A pointer to a 512 byte block of RAM to use for buffering, or 0 to remove a
                        previously provided buffer.

     \param bufferLength Must be 512 (unless \a buffer is 0, in which case \a bufferLength may also
                         be 0).  This argument is required for documentation and safety purposes; it
                         is checked but not otherwise used, since the buffer size must be 512.

     \blinks #E_API_ARGUMENT if \a bufferLength is something other than 512 or 0 when \a buffer is
     0.
   */
  bool setBlockBuffer(u8 * buffer, u32 bufferLength) ;

  /** Read \a length bytes into \a data, starting from disk address \a address.  Return \c true if
      all went well, otherwise return \c false and update #getState() to reflect the problem.

      \a length may be any value (that doesn't overrun RAM or disk), and neither \a address nor \a
      data have any alignment requirements.  

      However, the speed of this method depends on whether #setBlockBuffer(u8*,u32) has previously
      been called to supply a (non-null) block buffer.  If If it has \e not been called (or has been
      called most recently with a null argument), then this method performs an \e unbuffered block
      read operation, and so \e each \e call to this method will read at least 512 bytes from the
      disk, even if \a length is smaller than that.  As a consequence, using this method without a
      buffer to read, say, one byte at a time, would be \e extremely inefficient.  

      On the other hand, if a block buffer \e has been provided, then a buffered read operation is
      performed, and so reads of sequentially increasing addresses will be reasonably efficient no
      matter what \a length is used.

      For absolute maximum efficiency in this method, no block buffer should be provided, and \a
      address and \a length should both be multiples of 512.

      \param address Disk address (in bytes) to start reading data from, in the range of 0 to
                     #getByteCount()-\a length

      \param data RAM address to start writing data to.

      \param length Number of byts to transfer.

      \returns \c true if read succeeded, \c false otherwise

      \blinks #E_API_ARGUMENT if \a data equals 0 while \a length is nonzero.
  */
  bool read(u64 address, u8* data, u32 length) ;

  /** Read a block of data from the disk, storing some or all of it in \a buffer.  A single full
      block is always read by this method, but the optional arguments \a blockOffset and \a length
      control how much of that block, if any, is stored in \a bufer.  \a blockOffset, in the range
      of 0 to 512, determines how many of the disk block bytes should be skipped before beginning to
      store \a length bytes starting at \a buffer.  With default values, the entire block is stored.

      Return \c true if all went well, otherwise return \c false and update #getState() to reflect
      the problem.

      \a length and \a blockOffset may each have any value from 0 to 512, but note that this is an
      \e unbuffered block read operation, which will read a full 512 bytes from the disk even if \a
      length is smaller than that.

      As a consequence, using this method to read, say, one byte at a time would be \e extremely
      inefficient.  

      \param blockNumber Disk block (in units of 512 bytes per block) to read, in the range of 0 to
                     #getBlockCount()-1

      \param buffer RAM address to start writing data to, with at least \a length bytes of space available


      \param blockOffset Number of read bytes to skip before beginning to store them, in the range of
      0..512, default value 0.


      \param length Number of bytes to store into \a buffer, in the range of 0..512-\a blockOffset,
      default value 512.
  */
  bool readBlock(u32 blockNumber, u8* buffer, u32 blockOffset = 0, u32 length = 512) ;
  
  /** Write \a length bytes from \a data to disk, starting from disk address \a address.  Return \c true if
      all went well, otherwise return \c false and update #getState() to reflect the problem.

      The legal arguments to this command depend on whether #setBlockBuffer(u8*,u32) has been called
      to supply a (non-null) block buffer.  If it has \e not been called (or has been called most
      recently with a null argument), then both \a address and \a length \e must be a multiple of
      512, or the sketch will die blinking #E_API_ILLEGAL_STATE.

      On the other hand, if a block buffer \e has been provided, then \a length may be any value
      (that doesn't overrun RAM or disk), and \a address has no alignment requirements.  (\a data
      never has any alignment requirements.)

      When a block buffer is available, this method will perform \e buffered \e writes, which means
      that (some or all of) the data you supply \e may \e not have actually been written to the disk
      by the time that this method returns.  To be certain that all data has been written to disk, call #sync(), after writing, to force any buffered data to be written.

      \param address Disk address (in bytes) to start writing data to, in the range of 0 to
      #getByteCount()-\a length

      \param data RAM address to start reading data from.

      \param length Number of byts to transfer.

      \blinks #E_API_ILLEGAL_STATE unless a block buffer is available or both \a address and \a
      length are a multiple of 512.

      \return \c true if all went well, \c false otherwise.
  */
  bool write(u64 address, const u8* data, u32 length) ;

  /** Write a full \a block of data to disk block \a blockNumber, .  Return \c true if all went
      well, otherwise return \c false and update #getState() to reflect the problem.  That this is
      an unbuffered write not requiring a previous #setBlockBuffer() to provide a buffer (and making
      no use of such a buffer if it was provided).

      \param blockNumber Disk block (in units of 512 bytes per block) to write, in the range of 0 to
      #getBlockCount()-1

      \param block RAM address to read data from, containing 512 bytes of data.

      \returns \c true if write succeeded, \c false otherwise.

      \blinks #E_API_NULL_POINTER if \a buffer is null.

  */
  bool writeBlock(u32 blockNumber, const u8* buffer) ;

  /**
     Flush any pending buffered writes to disk.  Return \c true if all went well (whether or not any
     actual writing was performed), else return \c false and update #getState() to reflect the
     problem.

     Harmless to call if there are no writes pending, also harmless (but meaningless) to call unless
     a prior #setBlockBuffer() with a non-block argument call has been made.
   */
  bool sync() ;

  /**
     Return \c true if the disk is an 'Secure Digital High Capacity' card, \c false otherwise.
     Return value is only valid if #getState() returns #ACTIVE.
   */

  bool isSDHC() { return (flags&HC_CARD); }

  /**
     Turn on or off low-level SPI protocol logging (for internal debugging).
   */
  void setSpiLog(bool val) { if (val) flags |= SPI_LOG; else flags &= ~SPI_LOG; }

  /**
     Read and return the internal status register of the card.  Note the difference between this
     method, which always requests status information from the SD card itself, and #getState(),
     which returns information not about the card, but about the #SDRaw controller.

     Calling this method is probably the fastest way to check if a previously successfully
     #init()-ed card is still present and alive.

     The return value is the card status bits as defined by the SD Card specification, and will be
     zero in the normal case.
   */
  u32 readStatus() ;

private:
  enum { SHORT_TRIES = 50, LONG_TRIES = 50000 };

  enum {
    BLOCK_DIRTY = 0x01,
    HC_CARD     = 0x02,
    SPI_LOG     = 0x04,
    FLAG_RSRV3  = 0x08,
    FLAG_RSRV4  = 0x10,
    FLAG_RSRV5  = 0x20,
    FLAG_RSRV6  = 0x40,
    FLAG_RSRV7  = 0x80
  };
  u32 blockCapacity;            // Number of blocks that fit on the disk
  u32 cachedBlockNumber;        // Number of currently buffered block
  u8 * cachedBlock;             // Zero for no buffering or ptr to 512 bytes
  u8 flags;                     // Dirty bit
  u8 status;                    // Operational status
  u8 sdFace;                    // Face to power cycle to init card
  u8 sdCSel;                    // Pin for chip select
  u8 sdClk;                     // Pin for clock
  u8 sdMOSI;                    // Pin for master-out-slave-in
  u8 sdMISO;                    // Pin for master-in-slave-out

  void startTransaction() ;
  void endTransaction() ;

  bool dieWith(u32 newStatus) ;

  bool readRegister(u32 cmd, u8 reg[16]);

  void sendBitsSlow(u32 data, u32 bitCount) ;  // Used during init only
  u32 recvBitsSlow(u32 bitCount) ;             // Used during init only

  void sendBits(u32 bits, u32 bitCount) ;
  u32 recvBits(u32 bitCount) ;

  void sendByte(u8 data) { sendBits(data,8); }
  u8 recvByte() { return (u8) recvBits(8); }

  u8 sendCmd(u8 cmd, u32 arg) ;

  bool loadCache(u32 blockNumber) ;
  bool writeBuffered(u64 offset, const u8* buffer, u32 length) ;
  bool readBuffered(u64 offset, u8* buffer, u32 length) ;

};

#endif /* SFBSDRAW_H */
