// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright 2015 Microchip Technology Inc. (www.microchip.com)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

To request to license the code under the MLA license (www.microchip.com/mla_license), 
please contact mla_licensing@microchip.com
*******************************************************************************/
//DOM-IGNORE-END

#ifndef SDMMC_H
#define SDMMC_H

#include "FileSystem_config.h"
//#include "system.h"
#include <stdint.h>
#include <stdbool.h>

#include "fileio_media.h"

/*****************************************************************************/
/*                        Custom structures and definitions                  */
/*****************************************************************************/
//Definition for a structure used when calling either FILEIO_SD_AsyncReadTasks()
//function, or the FILEIO_SD_AsyncWriteTasks() function.
typedef struct
{
    uint16_t wNumBytes;         //Number of bytes to attempt to read or write in the next call to MDD_SDSPI_AsyncReadTasks() or MDD_SDSPI_AsyncWriteTasks.  May be updated between calls to the handler.
    uint32_t dwBytesRemaining; //Should be initialized to the total number of uint8_ts that you wish to read or write.  This value is allowed to be greater than a single block size of the media.
    uint8_t* pBuffer;          //Pointer to where the read/written uint8_ts should be copied to/from.  May be updated between calls to the handler function.
    uint32_t dwAddress;        //Starting block address to read or to write to on the media.  Should only get initialized, do not modify after that.
    uint8_t bStateVariable;    //State machine variable.  Should get initialized to ASYNC_READ_QUEUED or ASYNC_WRITE_QUEUED to start an operation.  After that, do not modify until the read or write is complete.
}FILEIO_SD_ASYNC_IO;

//Response codes for the FILEIO_SD_AsyncReadTasks() function.
#define FILEIO_SD_ASYNC_READ_COMPLETE             0x00
#define FILEIO_SD_ASYNC_READ_BUSY                 0x01
#define FILEIO_SD_ASYNC_READ_NEW_PACKET_READY     0x02
#define FILEIO_SD_ASYNC_READ_ERROR                0xFF

//FILEIO_SD_AsyncReadTasks() state machine variable values. These are used internally to sd_spi.c.
#define FILEIO_SD_ASYNC_READ_COMPLETE             0x00
#define FILEIO_SD_ASYNC_READ_QUEUED               0x01    //Initialize to this to start a read sequence
#define FILEIO_SD_ASYNC_READ_WAIT_START_TOKEN     0x03
#define FILEIO_SD_ASYNC_READ_NEW_PACKET_READY     0x02
#define FILEIO_SD_ASYNC_READ_ABORT                0xFE
#define FILEIO_SD_ASYNC_READ_ERROR                0xFF

//Possible return values when calling FILEIO_SD_AsyncWriteTasks()
#define FILEIO_SD_ASYNC_WRITE_COMPLETE        0x00
#define FILEIO_SD_ASYNC_WRITE_SEND_PACKET     0x02
#define FILEIO_SD_ASYNC_WRITE_BUSY            0x03
#define FILEIO_SD_ASYNC_WRITE_ERROR           0xFF

//FILEIO_SD_AsyncWriteTasks() state machine variable values. These are used internally to sd_spi.c.
#define FILEIO_SD_ASYNC_WRITE_COMPLETE            0x00
#define FILEIO_SD_ASYNC_WRITE_QUEUED              0x01    //Initialize to this to start a write sequence
#define FILEIO_SD_ASYNC_WRITE_TRANSMIT_PACKET     0x02
#define FILEIO_SD_ASYNC_WRITE_MEDIA_BUSY          0x03
#define FILEIO_SD_ASYNC_STOP_TOKEN_SENT_WAIT_BUSY 0x04
#define FILEIO_SD_ASYNC_WRITE_ABORT               0xFE
#define FILEIO_SD_ASYNC_WRITE_ERROR               0xFF


/*****************************************************************************/
/*                         Function pointer types                            */
/*****************************************************************************/

/*************************************************************************************
    Function:
        typedef void (*FILEIO_SD_CSSet)(uint8_t value)
        
    Summary:
        Prototype for a user-implemented function to set or 
        clear the SPI's chip select pin.

    Input:
        value - The value of the chip select pin (1 or 0)

    Return Values:
        None

    Description:
        Most functions in this driver require the user to implement the functions 
        that comprise a FILEIO_SD_DRIVE_CONFIG structure.  This function pointer 
        definition describes a function in this structure that will set/clear the 
        chip select pin.
    
    Remarks:
        None                                                  
  ***********************************************************************************/
typedef void (*FILEIO_SD_CSSet)(uint8_t value);

/*************************************************************************************
    Function:
        typedef bool (*FILEIO_SD_CDGet)(void);
        
    Summary:
        Prototype for a user-implemented function to get the current state of the  
        Card Detect pin, if one exists.

    Input:
        None

    Return Values:
        true if the card detect pin indicates the card is inserted, false otherwise.
        If the physical socket in use does not have a card detect pin, this 
        function should always return true.

    Description:
        Most functions in this driver require the user to implement the functions 
        that comprise a FILEIO_SD_DRIVE_CONFIG structure.  This function pointer 
        definition describes a function in this structure that will return the value 
        of a card detect pin.  These pins are a typical feature on the physical 
        sockets manufactured for SD card (not on the SD cards themselves).  On 
        some types of SD card (i.e. micro SD) this pin will not be available.
    
    Remarks:
        None                                                  
  ***********************************************************************************/
typedef bool (*FILEIO_SD_CDGet)(void);

/*************************************************************************************
    Function:
        typedef bool (*FILEIO_SD_WPGet)(void);
        
    Summary:
        Prototype for a user-implemented function to get the current state of the  
        Write Protect pin, if one exists.

    Input:
        None

    Return Values:
        true if the write protect pin indicates the card is inserted, false otherwise.
        If the physical socket in use does not have a write protect pin, this 
        function should always return false.

    Description:
        Most functions in this driver require the user to implement the functions 
        that comprise a FILEIO_SD_DRIVE_CONFIG structure.  This function pointer 
        definition describes a function in this structure that will return the value 
        of a write protect pin.  These pins are a typical feature on the physical 
        sockets manufactured for SD card (not on the SD cards themselves).  On 
        some types of SD card (i.e. micro SD) this pin will not be available.
    
    Remarks:
        None                                                  
  ***********************************************************************************/
typedef bool (*FILEIO_SD_WPGet)(void);

/*************************************************************************************
    Function:
        typedef void (*FILEIO_SD_PinConfigure)(void);
        
    Summary:
        Prototype for a user-implemented function to configure the pins used by 
        the SD card.

    Input:
        None

    Return Values:
        None.

    Description:
        Most functions in this driver require the user to implement the functions 
        that comprise a FILEIO_SD_DRIVE_CONFIG structure.  This function pointer 
        definition describes a function in this structure that will configure all of 
        the pins used by the SD Card.  The configuration may involve setting/clearing
        the TRIS bits, disabling the analog state of the pins, setting up peripheral 
        pin select, or other operations (depending on the device).
        The user must configure the chip select, card detect, and write protect pins.
        Optionally, configuration for the SPI pins (SDI, SDO, SCK) and SPI module 
        may be performed in this function, though it may make more sense to configure 
        those in another part of any given application.
    
    Remarks:
        None                                                  
  ***********************************************************************************/
typedef void (*FILEIO_SD_PinConfigure)(void);

// A configuration structure used by the SD-SPI driver functions to perform specific 
// tasks.
typedef struct
{
    uint8_t index;                                  // The numeric index of the SPI module to use (i.e. 1 for SPI1/SSP1, 2 for SPI2, SSP2,...)
    FILEIO_SD_CSSet csFunc;                         // Pointer to a user-implemented function to set/clear the chip select pins
    FILEIO_SD_CDGet cdFunc;                         // Pointer to a user-implemented function to get the status of the card detect pin
    FILEIO_SD_WPGet wpFunc;                         // Pointer to a user-implemented function to get the status of the write protect pin
    FILEIO_SD_PinConfigure configurePins;           // Pointer to a user-implemented function to configure the pins used by the SD Card
} FILEIO_SD_DRIVE_CONFIG;


/*****************************************************************************/
/*                                 Public Prototypes                         */
/*****************************************************************************/

/*********************************************************
  Function:
    bool FILEIO_SD_MediaDetect (FILEIO_SD_DRIVE_CONFIG * config)
  Summary:
    Determines whether an SD card is present
  Conditions:
    The FILEIO_SD_MediaDetect function pointer must be configured
    to point to this function in FSconfig.h
  Input:
    config - The given drive configuration
  Return Values:
    true -  Card detected
    false - No card detected
  Side Effects:
    None.
  Description:
    The FILEIO_SD_MediaDetect function determine if an SD card is connected to 
    the microcontroller.
    If the MEDIA_SOFT_DETECT is not defined, the detection is done by polling
    the SD card detect pin.
    The MicroSD connector does not have a card detect pin, and therefore a
    software mechanism must be used. To do this, the SEND_STATUS command is sent 
    to the card. If the card is not answering with 0x00, the card is either not 
    present, not configured, or in an error state. If this is the case, we try
    to reconfigure the card. If the configuration fails, we consider the card not 
    present (it still may be present, but malfunctioning). In order to use the 
    software card detect mechanism, the MEDIA_SOFT_DETECT macro must be defined.
    
  Remarks:
    None                                                  
  *********************************************************/
bool FILEIO_SD_MediaDetect(FILEIO_SD_DRIVE_CONFIG * config);

/*****************************************************************************
  Function:
    FILEIO_MEDIA_INFORMATION *  FILEIO_SD_MediaInitialize (void)
  Summary:
    Initializes the SD card.
  Conditions:
    The FILEIO_SD_MediaInitialize function pointer must be pointing to this function.
  Input:
    config - An SD Drive configuration structure pointer
  Return Values:
    The function returns a pointer to the FILEIO_MEDIA_INFORMATION structure.  The
    errorCode member may contain the following values:
        * MEDIA_NO_ERROR - The media initialized successfully
        * MEDIA_CANNOT_INITIALIZE - Cannot initialize the media.  
  Side Effects:
    None.
  Description:
    This function will send initialization commands to and SD card.
  Remarks:
    Psuedo code flow for the media initialization process is as follows:

-------------------------------------------------------------------------------------------
SD Card SPI Initialization Sequence (for physical layer v1.x or v2.0 device) is as follows:
-------------------------------------------------------------------------------------------
0.  Power up tasks
    a.  Initialize microcontroller SPI module to no more than 400kbps rate so as to support MMC devices.
    b.  Add delay for SD card power up, prior to sending it any commands.  It wants the 
        longer of: 1ms, the Vdd ramp time (time from 2.7V to Vdd stable), and 74+ clock pulses.
1.  Send CMD0 (GO_IDLE_STATE) with CS = 0.  This puts the media in SPI mode and software resets the SD/MMC card.
2.  Send CMD8 (SEND_IF_COND).  This requests what voltage the card wants to run at. 
    Note: Some cards will not support this command.
    a.  If illegal command response is received, this implies either a v1.x physical spec device, or not an SD card (ex: MMC).
    b.  If normal response is received, then it must be a v2.0 or later SD memory card.

If v1.x device:
-----------------
3.  Send CMD1 repeatedly, until initialization complete (indicated by R1 response uint8_t/idle bit == 0)
4.  Basic initialization is complete.  May now switch to higher SPI frequencies.
5.  Send CMD9 to read the CSD structure.  This will tell us the total flash size and other info which will be useful later.
6.  Parse CSD structure bits (based on v1.x structure format) and extract useful information about the media.
7.  The card is now ready to perform application data transfers.

If v2.0+ device:
-----------------
3.  Verify the voltage range is feasible.  If not, unusable card, should notify user that the card is incompatible with this host.
4.  Send CMD58 (Read OCR).
5.  Send CMD55, then ACMD41 (SD_SEND_OP_COND, with HCS = 1).
    a.  Loop CMD55/ACMD41 until R1 response uint8_t == 0x00 (indicating the card is no longer busy/no longer in idle state).  
6.  Send CMD58 (Get CCS).
    a.  If CCS = 1 --> SDHC card.
    b.  If CCS = 0 --> Standard capacity SD card (which is v2.0+).
7.  Basic initialization is complete.  May now switch to higher SPI frequencies.
8.  Send CMD9 to read the CSD structure.  This will tell us the total flash size and other info which will be useful later.
9.  Parse CSD structure bits (based on v2.0 structure format) and extract useful information about the media.
10. The card is now ready to perform application data transfers.
--------------------------------------------------------------------------------
********************************************************************************/
FILEIO_MEDIA_INFORMATION * FILEIO_SD_MediaInitialize(FILEIO_SD_DRIVE_CONFIG * config);

/*********************************************************
  Function:
    bool FILEIO_SD_MediaDeinitialize(
        FILEIO_SD_DRIVE_CONFIG * config)
  Summary:
    Disables the SD card
  Conditions:
    The FILEIO_SD_MediaDeinitialize function pointer is pointing 
    towards this function.
  Input:
    config - An SD Drive configuration structure pointer
  Return:
    true if successful, false otherwise
  Side Effects:
    None.
  Description:
    This function will disable the SPI port and deselect
    the SD card.
  Remarks:
    None
  *********************************************************/
bool FILEIO_SD_MediaDeinitialize(FILEIO_SD_DRIVE_CONFIG * config);

/*********************************************************
  Function:
    uint32_t FILEIO_SD_CapacityRead(
        FILEIO_SD_DRIVE_CONFIG * config)
  Summary:
    Determines the current capacity of the SD card
  Conditions:
    FILEIO_SD_MediaInitialize() is complete
  Input:
    config - An SD Drive configuration structure pointer
  Return:
    The capacity of the device
  Side Effects:
    None.
  Description:
    The FILEIO_SD_CapacityRead function is used by the
    USB mass storage class to return the total number
    of sectors on the card.
  Remarks:
    None
  *********************************************************/
uint32_t FILEIO_SD_CapacityRead(FILEIO_SD_DRIVE_CONFIG * config);

/*********************************************************
  Function:
    uint16_t FILEIO_SD_SectorSizeRead(
        FILEIO_SD_DRIVE_CONFIG * config)
  Summary:
    Determines the current sector size on the SD card
  Conditions:
    FILEIO_SD_MediaInitialize() is complete
  Input:
    config - An SD Drive configuration structure pointer
  Return:
    The size of the sectors for the physical media
  Side Effects:
    None.
  Description:
    The FILEIO_SD_SectorSizeRead function is used by the
    USB mass storage class to return the card's sector
    size to the PC on request.
  Remarks:
    None
  *********************************************************/
uint16_t FILEIO_SD_SectorSizeRead(FILEIO_SD_DRIVE_CONFIG * config);

/*********************************************************
  Function:
    void FILEIO_SD_IOInitialize (
        FILEIO_SD_DRIVE_CONFIG * config)
  Summary:
    Initializes the I/O lines connected to the card
  Conditions:
    FILEIO_SD_MediaInitialize() is complete.  The MDD_InitIO
    function pointer is pointing to this function.
  Input:
    config - An SD Drive configuration structure pointer
  Return:
    None
  Side Effects:
    None.
  Description:
    The FILEIO_SD_IOInitialize function initializes the I/O
    pins connected to the SD card.
  Remarks:
    None
  *********************************************************/
void FILEIO_SD_IOInitialize(FILEIO_SD_DRIVE_CONFIG * config);
//extern void FILEIO_Driver_IOInitialize(void);

/*****************************************************************************
  Function:
    uint8_t FILEIO_SD_SectorRead (uint32_t sector_addr, uint8_t * buffer)
  Summary:
    Reads a sector of data from an SD card.
  Conditions:
    The FILEIO_SD_SectorRead function pointer must be pointing towards this function.
  Input:
    config - An SD Drive configuration structure pointer
    sectorAddress - The address of the sector on the card.
    buffer -      The buffer where the retrieved data will be stored.  If
                  buffer is NULL, do not store the data anywhere.
  Return Values:
    true -  The sector was read successfully
    false - The sector could not be read
  Side Effects:
    None
  Description:
    The FILEIO_SD_SectorRead function reads a sector of data uint8_ts (512 uint8_ts) 
    of data from the SD card starting at the sector address and stores them in 
    the location pointed to by 'buffer.'
  Remarks:
    The card expects the address field in the command packet to be a uint8_t address.
    The sector_addr value is converted to a uint8_t address by shifting it left nine
    times (multiplying by 512).
    
    This function performs a synchronous read operation.  In other uint16_ts, this
    function is a blocking function, and will not return until either the data
    has fully been read, or, a timeout or other error occurred.
  ***************************************************************************************/
bool FILEIO_SD_SectorRead(FILEIO_SD_DRIVE_CONFIG * config, uint32_t sector_addr, uint8_t * buffer);

/*****************************************************************************
  Function:
    bool FILEIO_SD_SectorWrite (FILEIO_SD_DRIVE_CONFIG * config,
        uint32_t sector_addr, uint8_t * buffer, uint8_t allowWriteToZero)
  Summary:
    Writes a sector of data to an SD card.
  Conditions:
    The FILEIO_SD_SectorWrite function pointer must be pointing to this function.
  Input:
    config - An SD Drive configuration structure pointer
    sectorAddress -      The address of the sector on the card.
    buffer -           The buffer with the data to write.
    allowWriteToZero -
                     - true -  Writes to the 0 sector (MBR) are allowed
                     - false - Any write to the 0 sector will fail.
  Return Values:
    true -  The sector was written successfully.
    false - The sector could not be written.
  Side Effects:
    None.
  Description:
    The FILEIO_SD_SectorWrite function writes one sector of data (512 uint8_ts) 
    of data from the location pointed to by 'buffer' to the specified sector of 
    the SD card.
  Remarks:
    The card expects the address field in the command packet to be a uint8_t address.
    The sector_addr value is converted to a uint8_t address by shifting it left nine
    times (multiplying by 512).
  ***************************************************************************************/
bool FILEIO_SD_SectorWrite(FILEIO_SD_DRIVE_CONFIG * config, uint32_t sector_addr, uint8_t * buffer, bool allowWriteToZero);

/*******************************************************************************
  Function:
    uint8_t FILEIO_SD_WriteProtectStateGet
  Summary:
    Indicates whether the card is write-protected.
  Conditions:
    The FILEIO_SD_WriteProtectStateGet function pointer must be pointing to this function.
  Input:
    config - An SD Drive configuration structure pointer
  Return Values:
    true -  The card is write-protected
    false - The card is not write-protected
  Side Effects:
    None.
  Description:
    The FILEIO_SD_WriteProtectStateGet function will determine if the SD card is
    write protected by checking the electrical signal that corresponds to the
    physical write-protect switch.
  Remarks:
    None
*******************************************************************************/
bool FILEIO_SD_WriteProtectStateGet(FILEIO_SD_DRIVE_CONFIG * config);


uint8_t FILEIO_SD_AsyncReadTasks(FILEIO_SD_DRIVE_CONFIG * config, FILEIO_SD_ASYNC_IO*);
uint8_t FILEIO_SD_AsyncWriteTasks(FILEIO_SD_DRIVE_CONFIG * config, FILEIO_SD_ASYNC_IO*);



#endif
