/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "usbHost.h"

/* Definitions of physical drive number for each drive */
#define DEV_RAM		0	/* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC		1	/* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB		2	/* Example: Map USB MSD to physical drive 2 */


/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
    if(pdrv >= get_nums_msc_device()){
        return STA_NODISK;
    }
	return RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
    return disk_status(pdrv);
}



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

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
    int     size;
    int     rec_size;
    int     to;

    if(disk_status(pdrv) != RES_OK){
        return RES_NOTRDY;
    }

    rec_size = 0;
    while(count--){
        to=0;
        do {
            size=usb_msc_sector_read(pdrv, sector, buff+rec_size);
            to++;
        }while(size <=0 && to <=3);

        if(to > 3){
            return RES_ERROR;
        }
        sector++;
        rec_size += size;
    }
	return RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
    int     sent_size;
    int     res, to;

    if(disk_status(pdrv) != RES_OK){
        return RES_NOTRDY;
    }

    sent_size = 0;
    while(count--){
        to=0;
        do {
            res = usb_msc_sector_write(pdrv, sector, (uint8_t *)buff+sent_size);
            to++;
        }while(res == -1 && to <=3);

        if(to > 3){
            return RES_ERROR;
        }
        sector++;
        sent_size += 512;  // sector size = 512byte
    }
	return RES_OK;
}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
    uint32_t  last_sector;

    if(disk_status(pdrv) != RES_OK){
        return RES_NOTRDY;
    }

    // CTRL_SYNC          0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
    // GET_SECTOR_COUNT   1 /* Get media size (needed at FF_USE_MKFS == 1) */
    // GET_SECTOR_SIZE    2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
    // GET_BLOCK_SIZE     3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
    // CTRL_TRIM          4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
    
    switch(cmd){
        case CTRL_SYNC:
        case CTRL_TRIM:
            ; // do nothing
            return RES_OK;

        case GET_SECTOR_COUNT:
            last_sector = usb_msc_capacity_read(pdrv);
            if(last_sector == 0) return RES_ERROR;
            
            *((uint32_t *)buff) = last_sector+1;
            return RES_OK;
            
        case GET_SECTOR_SIZE:
            *((int16_t *)buff) = 512;
            return RES_OK;
            
        case GET_BLOCK_SIZE:
            *((uint32_t *)buff) = 1; // unknown = 1
            return RES_OK;
        
        default:
            break;
    }
    
	return RES_PARERR;
}


/*** end of file **************************************************************/