// 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

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

/*****************************************************************/
/*                  Structures and defines                       */
/*****************************************************************/

#ifdef __XC8__
    // Description: This macro is used to initialize a PIC18 SPI module with a 4x prescale divider
    #define   SYNC_MODE_FAST    0x00
    // Description: This macro is used to initialize a PIC18 SPI module with a 16x prescale divider
    #define   SYNC_MODE_MED     0x01
    // Description: This macro is used to initialize a PIC18 SPI module with a 64x prescale divider
    #define   SYNC_MODE_SLOW    0x02
#elif defined __XC32__
    // Description: This macro is used to initialize a PIC32 SPI module
    #define   SYNC_MODE_FAST    0x3E
    // Description: This macro is used to initialize a PIC32 SPI module
    #define   SYNC_MODE_SLOW    0x3C
#else
    // Description: This macro indicates the SPI enable bit for 16-bit PICs
    #ifndef MASTER_ENABLE_ON
        #define  MASTER_ENABLE_ON       0x0020
    #endif

    // Description: This macro is used to initialize a 16-bit PIC SPI module
    #ifndef SYNC_MODE_FAST
        #define   SYNC_MODE_FAST    0x3E
    #endif
    // Description: This macro is used to initialize a 16-bit PIC SPI module
    #ifndef SYNC_MODE_SLOW
        #define   SYNC_MODE_SLOW    0x3C
    #endif

    // Description: This macro is used to initialize a 16-bit PIC SPI module secondary prescaler
    #ifndef SEC_PRESCAL_1_1
        #define  SEC_PRESCAL_1_1        0x001c
    #endif
    // Description: This macro is used to initialize a 16-bit PIC SPI module primary prescaler
    #ifndef PRI_PRESCAL_1_1
        #define  PRI_PRESCAL_1_1        0x0003
    #endif
#endif


// Description: This macro represents an SD card start single data block token (used for single block writes)
#define FILEIO_SD_DATA_START_TOKEN                  0xFE

// Description: This macro represents an SD card start multi-block data token (used for multi-block writes)
#define FILEIO_SD_DATA_START_MULTI_BLOCK_TOKEN      0xFC

// Description: This macro represents an SD card stop transmission token.  This is used when finishing a multi block write sequence.
#define FILEIO_SD_DATA_STOP_TRAN_TOKEN              0xFD

// Description: This macro represents an SD card data accepted token
#define FILEIO_SD_DATA_ACCEPTED                     0x05

// Description: This macro indicates that the SD card expects to transmit or receive more data
#define FILEIO_SD_MORE_DATA_EXPECTED                !0

// Description: This macro indicates that the SD card does not expect to transmit or receive more data
#define FILEIO_SD_NO_DATA_EXPECTED                  0

// Description: This macro represents a floating SPI bus condition
#define FILEIO_SD_FLOATING_BUS_TOKEN                0xFF

// The SDMMC Commands

// Description: This macro defines the command code to reset the SD card
#define     FILEIO_SD_COMMAND_GO_IDLE_STATE                          0
// Description: This macro defines the command code to initialize the SD card
#define     FILEIO_SD_COMMAND_SEND_OP_COND                           1
// Description: This macro defined the command code to check for sector addressing
#define     FILEIO_SD_COMMAND_SEND_IF_COND                           8
// Description: This macro defines the command code to get the Card Specific Data
#define     FILEIO_SD_COMMAND_SEND_CSD                               9
// Description: This macro defines the command code to get the Card Information
#define     FILEIO_SD_COMMAND_SEND_CID                               10
// Description: This macro defines the command code to stop transmission during a multi-block read
#define     FILEIO_SD_COMMAND_STOP_TRANSMISSION                      12
// Description: This macro defines the command code to get the card status information
#define     FILEIO_SD_COMMAND_SEND_STATUS                            13
// Description: This macro defines the command code to set the block length of the card
#define     FILEIO_SD_COMMAND_SET_BLOCK_LENGTH                       16
// Description: This macro defines the command code to read one block from the card
#define     FILEIO_SD_COMMAND_READ_SINGLE_BLOCK                      17
// Description: This macro defines the command code to read multiple blocks from the card
#define     FILEIO_SD_COMMAND_READ_MULTI_BLOCK                       18
// Description: This macro defines the command code to tell the media how many blocks to pre-erase (for faster multi-block writes to follow)
//Note: This is an "application specific" command.  This tells the media how many blocks to pre-erase for the subsequent WRITE_MULTI_BLOCK
#define     FILEIO_SD_COMMAND_SET_WRITE_BLOCK_ERASE_COUNT            23
// Description: This macro defines the command code to write one block to the card
#define     FILEIO_SD_COMMAND_WRITE_SINGLE_BLOCK                     24
// Description: This macro defines the command code to write multiple blocks to the card
#define     FILEIO_SD_COMMAND_WRITE_MULTI_BLOCK                      25
// Description: This macro defines the command code to set the address of the start of an erase operation
#define     FILEIO_SD_COMMAND_TAG_SECTOR_START                       32
// Description: This macro defines the command code to set the address of the end of an erase operation
#define     FILEIO_SD_COMMAND_TAG_SECTOR_END                         33
// Description: This macro defines the command code to erase all previously selected blocks
#define     FILEIO_SD_COMMAND_ERASE                                  38
//Description: This macro defines the command code to intitialize an SD card and provide the CSD register value.
//Note: this is an "application specific" command (specific to SD cards) and must be preceded by cmdAPP_CMD.
#define     FILEIO_SD_COMMAND_SD_SEND_OP_COND                        41
// Description: This macro defines the command code to begin application specific command inputs
#define     FILEIO_SD_COMMAND_APP_CMD                                55
// Description: This macro defines the command code to get the OCR register information from the card
#define     FILEIO_SD_COMMAND_READ_OCR                               58
// Description: This macro defines the command code to disable CRC checking
#define     FILEIO_SD_COMMAND_CRC_ON_OFF                             59


// Description: Enumeration of different SD response types
typedef enum
{
    FILEIO_SD_RESPONSE_R1,     // R1 type response
    FILEIO_SD_RESPONSE_R1b,    // R1b type response
    FILEIO_SD_RESPONSE_R2,     // R2 type response
    FILEIO_SD_RESPONSE_R3,     // R3 type response
    FILEIO_SD_RESPONSE_R7      // R7 type response
}RESP;

// Summary: SD card command data structure
// Description: The FILEIO_SD_COMMAND structure is used to create a command table of information needed for each relevant SD command
typedef struct
{
    uint8_t      CmdCode;          // The command code
    uint8_t      CRC;              // The CRC value for that command
    RESP    responsetype;       // The response type
    uint8_t    moredataexpected;   // Set to MOREDATA or NODATA, depending on whether more data is expected or not
} FILEIO_SD_COMMAND;


// Summary: An SD command packet
// Description: This union represents different ways to access an SD card command packet
typedef union
{
    // This structure allows array-style access of command uint8_ts
    struct
    {
        #ifdef __XC8__
            uint8_t field[6];      // uint8_t array
        #else
            uint8_t field[7];
        #endif
    };
    // This structure allows uint8_t-wise access of packet command uint8_ts
    struct
    {
        uint8_t crc;               // The CRC uint8_t
        #if defined __XC16__
            uint8_t c30filler;     // Filler space (since bitwise declarations can't cross a uint16_t boundary)
        #elif defined __XC32__
            uint8_t c32filler[3];  // Filler space (since bitwise declarations can't cross a uint32_t boundary)
        #endif
        
        uint8_t addr0;             // Address uint8_t 0
        uint8_t addr1;             // Address uint8_t 1
        uint8_t addr2;             // Address uint8_t 2
        uint8_t addr3;             // Address uint8_t 3
        uint8_t cmd;               // Command code uint8_t
    };
    // This structure allows bitwise access to elements of the command uint8_ts
    struct
    {
        uint8_t  END_BIT:1;        // Packet end bit
        uint8_t  CRC7:7;           // CRC value
        uint32_t     address;      // Address
        uint8_t  CMD_INDEX:6;      // Command code
        uint8_t  TRANSMIT_BIT:1;   // Transmit bit
        uint8_t  START_BIT:1;      // Packet start bit
    };
} FILEIO_SD_CMD_PACKET;


// Summary: The format of an R1 type response
// Description: This union represents different ways to access an SD card R1 type response packet.
typedef union
{
    uint8_t _byte;                         // uint8_t-wise access
    // This structure allows bitwise access of the response
    struct
    {
        unsigned IN_IDLE_STATE:1;       // Card is in idle state
        unsigned ERASE_RESET:1;         // Erase reset flag
        unsigned ILLEGAL_CMD:1;         // Illegal command flag
        unsigned CRC_ERR:1;             // CRC error flag
        unsigned ERASE_SEQ_ERR:1;       // Erase sequence error flag
        unsigned ADDRESS_ERR:1;         // Address error flag
        unsigned PARAM_ERR:1;           // Parameter flag   
        unsigned B7:1;                  // Unused bit 7
    };
} FILEIO_SD_RESPONSE_1;

// Summary: The format of an R2 type response
// Description: This union represents different ways to access an SD card R2 type response packet
typedef union
{
    uint16_t _uint16_t;
    struct
    {
        uint8_t      _byte0;
        uint8_t      _byte1;
    };
    struct
    {
        unsigned IN_IDLE_STATE:1;
        unsigned ERASE_RESET:1;
        unsigned ILLEGAL_CMD:1;
        unsigned CRC_ERR:1;
        unsigned ERASE_SEQ_ERR:1;
        unsigned ADDRESS_ERR:1;
        unsigned PARAM_ERR:1;
        unsigned B7:1;
        unsigned CARD_IS_LOCKED:1;
        unsigned WP_ERASE_SKIP_LK_FAIL:1;
        unsigned ERROR:1;
        unsigned CC_ERROR:1;
        unsigned CARD_ECC_FAIL:1;
        unsigned WP_VIOLATION:1;
        unsigned ERASE_PARAM:1;
        unsigned OUTRANGE_CSD_OVERWRITE:1;
    };
} FILEIO_SD_RESPONSE_2;

// Summary: The format of an R7 or R3 type response
// Description: This union represents different ways to access an SD card R7 type response packet.
typedef union
{
    struct
    {
        uint8_t _byte;                         // byte-wise access
        union
        {
            //Note: The SD card argument response field is 32-bit, big endian format.
            //However, the C compiler stores 32-bit values in little endian in RAM.
            //When writing to the _returnVal/argument bytes, make sure to byte
            //swap the order from which it arrived over the SPI from the SD card.
            uint32_t _returnVal;
            struct
            {
                uint8_t _byte0;
                uint8_t _byte1;
                uint8_t _byte2;
                uint8_t _byte3;
            };    
        }argument;    
    } bytewise;
    // This structure allows bitwise access of the response
    struct
    {
        struct
        {
            unsigned IN_IDLE_STATE:1;       // Card is in idle state
            unsigned ERASE_RESET:1;         // Erase reset flag
            unsigned ILLEGAL_CMD:1;         // Illegal command flag
            unsigned CRC_ERR:1;             // CRC error flag
            unsigned ERASE_SEQ_ERR:1;       // Erase sequence error flag
            unsigned ADDRESS_ERR:1;         // Address error flag
            unsigned PARAM_ERR:1;           // Parameter flag   
            unsigned B7:1;                  // Unused bit 7
        }bits;
        uint32_t _returnVal;
    } bitwise;
} FILEIO_SD_RESPONSE_7;

// Summary: A union of responses from an SD card
// Description: The FILEIO_SD_RESPONSE union represents any of the possible responses that an SD card can return after
//              being issued a command.
typedef union
{
    FILEIO_SD_RESPONSE_1  r1;  
    FILEIO_SD_RESPONSE_2  r2;
    FILEIO_SD_RESPONSE_7  r7;
}FILEIO_SD_RESPONSE;


// Description: A delay prescaler
#define FILEIO_SD_DELAY_PRESCALER       (uint8_t)8

// Description: An approximation of the number of cycles per delay loop of overhead
#define FILEIO_SD_DELAY_OVERHEAD        (uint8_t)5

// Description: An approximate calculation of how many times to loop to delay 1 ms in the Delayms function
#define FILEIO_SD_MILLISECOND_DELAY     (uint16_t)((SYS_CLK_FrequencyInstructionGet()/FILEIO_SD_DELAY_PRESCALER/(uint16_t)1000) - FILEIO_SD_DELAY_OVERHEAD)


// Description: Media Response Delay Timeout Values
#define FILEIO_SD_NCR_TIMEOUT     (uint16_t)20          //uint8_t times before command response is expected (must be at least 8)
#define FILEIO_SD_NAC_TIMEOUT     (uint32_t)0x40000     //SPI uint8_t times we should wait when performing read operations (should be at least 100ms for SD cards)
#define FILEIO_SD_WRITE_TIMEOUT   (uint32_t)0xA0000     //SPI uint8_t times to wait before timing out when the media is performing a write operation (should be at least 250ms for SD cards).


// Summary: An enumeration of SD commands
// Description: This enumeration corresponds to the position of each command in the sdmmc_cmdtable array
//              These macros indicate to the FILEIO_SD_SendCmd function which element of the sdmmc_cmdtable array
//              to retrieve command code information from.
typedef enum
{
    FILEIO_SD_GO_IDLE_STATE,
    FILEIO_SD_SEND_OP_COND,
    FILEIO_SD_SEND_IF_COND,
    FILEIO_SD_SEND_CSD,
    FILEIO_SD_SEND_CID,
    FILEIO_SD_STOP_TRANSMISSION,
    FILEIO_SD_SEND_STATUS,
    FILEIO_SD_SET_BLOCK_LENGTH,
    FILEIO_SD_READ_SINGLE_BLOCK,
    FILEIO_SD_READ_MULTI_BLOCK,
    FILEIO_SD_WRITE_SINGLE_BLOCK,
    FILEIO_SD_WRITE_MULTI_BLOCK,
    FILEIO_SD_TAG_SECTOR_START,
    FILEIO_SD_TAG_SECTOR_END,
    FILEIO_SD_ERASE,
    FILEIO_SD_APP_CMD,
    FILEIO_SD_READ_OCR,
    FILEIO_SD_CRC_ON_OFF,
    FILEIO_SD_SD_SEND_OP_COND,
    FILEIO_SD_SET_WRITE_BLOCK_ERASE_COUNT
} FILEIO_SD_COMMAND_INDEX;


#define FILEIO_SD_MODE_NORMAL  0
#define FILEIO_SD_MODE_HC      1








//Constants
#define FILEIO_SD_MEDIA_BLOCK_SIZE            512u  //Should always be 512 for v1 and v2 devices.
#define FILEIO_SD_WRITE_RESPONSE_TOKEN_MASK   0x1F  //Bit mask to AND with the write token response uint8_t from the media, to clear the don't care bits.


/***************************************************************************/
/*                               Macros                                    */
/***************************************************************************/

// Description: A macro to send clock cycles to dummy-write the CRC
#define FILEIO_SD_CRCSend(i)              DRV_SPI_Put(i,0xFF);DRV_SPI_Put(i,0xFF);

// Description: A macro to send 8 clock cycles for SD timing requirements
#define FILEIO_SD_Send8ClockCycles(i)       DRV_SPI_Put(i,0xFF);

/*****************************************************************************/
/*                            Private Prototypes                             */
/*****************************************************************************/


