/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/

#include "board.h"
#include "memories.h"

#include "diskio.h"
#include "integer.h"
#include "fatfs_config.h"

#include <string.h>
#include <stdio.h>
#include <assert.h>

#define MAX_MEDS        1
extern Media medias[MAX_MEDS];


/*-----------------------------------------------------------------------*/
/* Initialize a Drive                                                    */
/*-----------------------------------------------------------------------*/


DSTATUS disk_initialize (
	BYTE drv				/* Physical drive number (0..) */
)
{
    DSTATUS stat = STA_NOINIT;

    switch (drv)
    {
        case DRV_SDRAM :
            stat = 0;
            break;

        case DRV_MMC :
            stat = 0;
            break;

        case DRV_NAND:
            stat = 0;
            break;
    }

    return stat;
}

/*-----------------------------------------------------------------------*/
/* Return Disk Status                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
    BYTE drv        /* Physical drive number (0..) */
)
{
    DSTATUS stat=STA_NOINIT;

    switch (drv)
    {
        case DRV_SDRAM :
            stat = 0;  // ok
            break;

        case DRV_MMC :
            stat = 0;  // ok
            break;
        case DRV_NAND:
            stat = 0;
            break;
    }

    return stat;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE drv,		/* Physical drive number (0..) */
	BYTE *buff,		/* Data buffer to store read data */
	DWORD sector,	/* Sector address (LBA) */
	BYTE count		/* Number of sectors to read (1..255) */
)
{
    unsigned char result;
    DRESULT res = RES_ERROR;

    unsigned int addr, len;
    if (medias[drv].blockSize < SECTOR_SIZE_DEFAULT)
    {
        addr = sector * (SECTOR_SIZE_DEFAULT / medias[drv].blockSize);
        len  = count * (SECTOR_SIZE_DEFAULT / medias[drv].blockSize);
    }
    else
    {
        addr = sector;
        len  = count;
    }

    result = MED_Read(&medias[drv], addr, (void*)buff, len, NULL, NULL);

    if( result == MED_STATUS_SUCCESS )
    {
        res = RES_OK;
    }
    else
    {
        TRACE_ERROR("MED_Read pb: 0x%X\n\r", result);
        res = RES_ERROR;
    }
   return res;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/
/* The FatFs module will issue multiple sector transfer request
/  (count > 1) to the disk I/O layer. The disk function should process
/  the multiple sector transfer properly Do. not translate it into
/  multiple single sector transfers to the media, or the data read/write
/  performance may be drasticaly decreased. */

#if _READONLY == 0
DRESULT disk_write (
	BYTE drv,			/* Physical drive number (0..) */
	const BYTE *buff,	/* Data to be written */
	DWORD sector,		/* Sector address (LBA) */
	BYTE count			/* Number of sectors to write (1..255) */
)
{
    DRESULT res=RES_PARERR;
    unsigned int result;
    void * tmp;
    tmp = (void *) buff;

    unsigned int addr, len;
    if (medias[drv].blockSize < SECTOR_SIZE_DEFAULT)
    {
        addr = sector * (SECTOR_SIZE_DEFAULT / medias[drv].blockSize);
        len  = count * (SECTOR_SIZE_DEFAULT / medias[drv].blockSize);
    }
    else
    {
        addr = sector;
        len  = count;
    }

    result = MED_Write(&medias[drv], addr, (void*)tmp, len, NULL, NULL);

    if( result == MED_STATUS_SUCCESS )
    {
        res = RES_OK;
    }
    else
    {
        TRACE_ERROR("MED_Write pb: 0x%X\n\r", result);
        res = RES_ERROR;
    }

    return res;
}
#endif /* _READONLY */

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
// Command    Description
//
//CTRL_SYNC    Make sure that the disk drive has finished pending write process.
// When the disk I/O module has a write back cache, flush the dirty sector immediately.
// In read-only configuration, this command is not needed.
//
//GET_SECTOR_COUNT    Returns total sectors on the drive into the DWORD variable pointed by Buffer.
// This command is used in only f_mkfs function.
//
//GET_BLOCK_SIZE    Returns erase block size of the memory array in unit
// of sector into the DWORD variable pointed by Buffer.
// When the erase block size is unknown or magnetic disk device, return 1.
// This command is used in only f_mkfs function.
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
    BYTE drv,        /* Physical drive number (0..) */
    BYTE ctrl,        /* Control code */
    void *buff        /* Buffer to send/receive control data */
)
{
    DRESULT res=RES_PARERR;

    switch (drv)
    {
        case DRV_SDRAM :
        switch (ctrl)
        {
            case GET_BLOCK_SIZE:
                *(DWORD*)buff = 1;
                res = RES_OK;
                break;

            case GET_SECTOR_COUNT :   /* Get number of sectors on the disk (DWORD) */
                if (medias[DRV_SDRAM].blockSize < SECTOR_SIZE_DEFAULT)
                {
                    *(DWORD*)buff = (DWORD)(medias[DRV_SDRAM].size /
                                            (SECTOR_SIZE_DEFAULT /
                                            medias[DRV_SDRAM].blockSize));
                }
                else
                {
                    *(DWORD*)buff = (DWORD)(medias[DRV_SDRAM].size);
                }
                res = RES_OK;
                break;

            case GET_SECTOR_SIZE :   /* Get sectors on the disk (WORD) */
                if (medias[DRV_SDRAM].blockSize < SECTOR_SIZE_DEFAULT)
                {
                    *(WORD*)buff = SECTOR_SIZE_DEFAULT;
                }
                else
                {
                    *(WORD*)buff = medias[DRV_SDRAM].blockSize;
                }
                res = RES_OK;
                break;

            case CTRL_SYNC :   /* Make sure that data has been written */
                res = RES_OK;
                break;

            default:
                res = RES_PARERR;
        }
        break;

        case DRV_MMC :
        switch (ctrl)
        {
            case GET_BLOCK_SIZE:
                *(DWORD*)buff = 1;
                res = RES_OK;
                break;

            case GET_SECTOR_COUNT :   /* Get number of sectors on the disk (DWORD) */
                if (medias[DRV_MMC].blockSize < SECTOR_SIZE_DEFAULT)
                {
                    *(DWORD*)buff = (DWORD)(medias[DRV_MMC].size /
                                                (SECTOR_SIZE_DEFAULT /
                                                medias[DRV_MMC].blockSize));
                }
                else
                {
                    *(DWORD*)buff = (DWORD)(medias[DRV_MMC].size);
                }
                res = RES_OK;
                break;

            case GET_SECTOR_SIZE :   /* Get sectors on the disk (WORD) */
                if (medias[DRV_MMC].blockSize < SECTOR_SIZE_DEFAULT)
                {
                    *(WORD*)buff = SECTOR_SIZE_DEFAULT;
                }
                else
                {
                    *(WORD*)buff = medias[DRV_MMC].blockSize;
                }
                res = RES_OK;
                break;

            case CTRL_SYNC :   /* Make sure that data has been written */
                res = RES_OK;
                break;

            default:
                res = RES_PARERR;
        }
        break;

        case DRV_NAND :
            switch (ctrl)
            {
                case GET_BLOCK_SIZE:
                    *(DWORD*)buff = 1;
                    res = RES_OK;
                    break;

                case GET_SECTOR_COUNT :   /* Get number of sectors on the disk (DWORD) */
                    if (medias[DRV_NAND].blockSize < SECTOR_SIZE_DEFAULT)
                    {
                        *(DWORD*)buff = (DWORD)(medias[DRV_NAND].size /
                                                (SECTOR_SIZE_DEFAULT /
                                                medias[DRV_NAND].blockSize));
                    }
                    else
                    {
                        *(DWORD*)buff = (DWORD)(medias[DRV_NAND].size);
                    }
                    res = RES_OK;
                    break;

                case GET_SECTOR_SIZE :	 /* Get sectors on the disk (WORD) */
                    if (medias[DRV_NAND].blockSize < SECTOR_SIZE_DEFAULT)
                    {
                        *(WORD*)buff = SECTOR_SIZE_DEFAULT;
                    }
                    else
                    {
                        *(WORD*)buff = medias[DRV_NAND].blockSize;
                    }
                    res = RES_OK;
                    break;

                case CTRL_SYNC :   /* Make sure that data has been written */
                    MED_Flush(&medias[DRV_NAND]);
                    res = RES_OK;
                    break;

                default:
                    res = RES_PARERR;
        }
    }
   return res;
}

//------------------------------------------------------------------------------
/// Current time is returned with packed into a DWORD value.
/// The bit field is as follows:
///   bit31:25  Year from 1980 (0..127)
///   bit24:21  Month (1..12)
///   bit20:16  Day in month(1..31)
///   bit15:11  Hour (0..23)
///   bit10:5   Minute (0..59)
///   bit4:0    Second / 2 (0..29)
//------------------------------------------------------------------------------
DWORD get_fattime (void)
{
    unsigned int time;

    time =  ((2010-1980)<<25)
          | ( 9<<21)
          | (15<<16)
          | (17<<11)
          | (45<<5)
          | ((59/2)<<0);

    return time;
}



