/**
 * @file hv_drv_UsbCoreUtils.c
 * @brief This is usb app layer driver.
 * @details 
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230417
 * @copyright Copyright(c),2022-9, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date             <th>Details
 * <tr><td>HiView SoC Software Team   <td>20230417       <td>Create and first Version.
 * </table>
 **/

#include "hv_drv_UsbCoreUtils.h"
#include "hv_drv_UsbPortingTypes.h"
#include "hv_drv_UsbCoreHub.h"
#include "hv_drv_UsbFatfsDiskIo.h"
#include "hv_drv_Flash.h"
#include "hv_vos_Cache.h"

#define HV_DRV_USB_STORAGE_CLASS        0x08
#define HV_DRV_USB_STORAGE_SUBCLASS     0x06
#define HV_DRV_USB_STORAGE_PROTOCOL     80

static HvDrvUsbType s_stUsbType = {0};
static BOOL s_bUsbConnected = HV_FALSE;


void Hv_Drv_USB_SetDeviceType(UCHAR8 ucClass, UCHAR8 ucSubClass, UCHAR8 ucProtocol)
{
    s_stUsbType.ucClass = ucClass;
    s_stUsbType.ucSubClass = ucSubClass;
    s_stUsbType.ucProtocol = ucProtocol;
}

UCHAR8 Hv_Drv_USB_GetClass(void)
{
    return s_stUsbType.ucClass;
}

UCHAR8 Hv_Drv_USB_GetSubClass(void)
{
    return s_stUsbType.ucSubClass;
}

UCHAR8 Hv_Drv_USB_GetProtocol(void)
{
    return s_stUsbType.ucProtocol;
}

BOOL Hv_Drv_USB_CheckStorageDev(void)
{
    BOOL bValid = HV_FALSE;
    if((s_stUsbType.ucClass == HV_DRV_USB_STORAGE_CLASS) 
        && (s_stUsbType.ucSubClass == HV_DRV_USB_STORAGE_SUBCLASS) 
        && (s_stUsbType.ucProtocol == HV_DRV_USB_STORAGE_PROTOCOL))
    {
        bValid = HV_TRUE;
    }
    return bValid;
}


void Hv_Drv_USB_SetConnect(BOOL bStatus)
{
    s_bUsbConnected = bStatus;
}

BOOL Hv_Drv_USB_GetConnect(void)
{
    return s_bUsbConnected;
}

Status Hv_Drv_USB_MountDev(FATFS *pstFatfs)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_mount(pstFatfs, "", 1) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}

BOOL Hv_Drv_USB_GetMounted(const FATFS* pstFatfs)
{
    BOOL bRet = HV_FALSE;
    
    if(pstFatfs->fs_type != 0)
    {
        bRet = HV_TRUE;
    }
    return bRet;
}

Status Hv_Drv_USB_FindFile(FIL *       pstFile, const TCHAR *pcPath)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_open(pstFile, pcPath, FA_READ) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}


UINT32 Hv_Drv_USB_GetFileSize(FIL *       pstFile)
{
    UINT32 uiFileSize = 0;
    if(pstFile != NULL)
    {
        uiFileSize = f_size(pstFile);
    }
    
    return uiFileSize;
}

Status Hv_Drv_USB_CloseFile(FIL *       pstFile)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_close(pstFile) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}


Status Hv_Drv_USB_UnmountDev(void)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_mount(NULL, "", 0) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}

Status Hv_Drv_USB_SetFileSeek(FIL *pstFile, FSIZE_t offset)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_lseek(pstFile, offset) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}

Status Hv_Drv_USB_ReadFile(FIL *pstFile, void *buff, UINT32 uiRdLen, UINT32 *uiRdLenRet)
{
    Status   uiStatus = HV_FAILURE;
    
    if(f_read(pstFile, buff, uiRdLen, uiRdLenRet) == FR_OK)
    {
        uiStatus = HV_SUCCESS;
    }
    
    return uiStatus;
}


VOID Hv_Drv_USB_ListFiles(const char* path) 
{
    FRESULT res;
    DIR dir;          //folder name
    FILINFO fno;      //file node info

    //打开指定名字的文件夹
    res = f_opendir(&dir, path);
    if (res != FR_OK)
    {
        return;
    }

    //读取目录项
    for (;;)
    {
        res = f_readdir(&dir, &fno);
        if (res != FR_OK || fno.fname[0] == 0)
        {
            break; //错误或目录结束
        }

        //跳过 "." 和 ".."
        if (fno.fname[0] == '.' && (fno.fname[1] == 0 || (fno.fname[1] == '.' && fno.fname[2] == 0)))
        {
            continue;
        }

        //获取文件名，区分LFN和SFN
#if FF_USE_LFN
        //长文件名存在且非空
        if (fno.fname[0] != 0)
        {
            HV_LOGI("lfn: %s", fno.fname); //长文件名
        } 
        else
        {
            HV_LOGI("sfn: %s", fno.altname); //回退到短文件名
        }
#else
        //未启用 LFN，直接打印短文件名
        HV_LOGI("only sfn: %s", fno.fname);
#endif
    }

    //关闭目录
    f_closedir(&dir);
}

