#include  <stdio.h> 

#include "stm32f4xx.h"
#include "main.h"
// #include "config.h"
#include "elog.h"

#include "bsp_driver_sd.h"
#include "fatfs.h"


HAL_SD_CardInfoTypeDef  SDCardInfo;           
extern SD_HandleTypeDef hsd;
 
FATFS fs; //工作空间
FIL fil; // 文件项目

extern void printf_sdcard_info(void);
extern int Init_FatFas_Mount(void);
extern int creat_file(char * filename);
extern int open_file(char * filename);
extern int close_file( );
extern uint8_t BSP_SD_Init(void);


uint8_t BSP_SD_Init(void)
{
  uint8_t sd_state = MSD_OK;
  /* Check if the SD card is plugged in the slot */
  if (BSP_SD_IsDetected() != SD_PRESENT)
  {
    return MSD_ERROR;
  }
  /* HAL SD initialization */
  sd_state = HAL_SD_Init(&hsd);
  /* Configure SD Bus width (4 bits mode selected) */
  if (sd_state == MSD_OK)
  {
        hsd.Init.ClockDiv = 6;
        // hsd.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;
    /* Enable wide operation */
    if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
    {
      sd_state = MSD_ERROR;
    }
  }

  return sd_state;
}

void printf_sdcard_info(void)
{
	uint64_t CardCap;      	//SD卡容量
	HAL_SD_CardCIDTypeDef SDCard_CID; 
    char * card_type[8] = {0};

	HAL_SD_GetCardCID(&hsd,&SDCard_CID);	//获取CID
	HAL_SD_GetCardInfo(&hsd,&SDCardInfo);                    //获取SD卡信息
	CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize);	//计算SD卡容量
	switch(SDCardInfo.CardType)
	{
		case CARD_SDSC:
		{
			if(SDCardInfo.CardVersion == CARD_V1_X)
            {
                memcpy(card_type, (void*)("SDSC V1"),7);
				// printf("Card Type:SDSC V1\r\n");
            }

			else  if (SDCardInfo.CardVersion == CARD_V2_X)
            {
                memcpy(card_type, (void*)("SDSC V2"),7);
				// printf("Card Type:SDSC V2\r\n");
            }
		    break;
		}

		case CARD_SDHC_SDXC:
        {
            memcpy(card_type, (void*)("SDHC"),4);
            printf("Card Type:SDHC\r\n");
            break;
        }

		default:break;
	}	
#if 1		
    log_i("Card Type:           %s \r\n",card_type);				//card 类型	
    log_i("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID);				//制造商ID	
 	log_i("CardVersion:         %d \r\n",(uint32_t)(SDCardInfo.CardVersion));		//卡版本号
	log_i("Class:               %d \r\n",(uint32_t)(SDCardInfo.Class));		    //
 	log_i("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd);					//卡相对地址
	log_i("Card BlockNbr:       %d \r\n",SDCardInfo.BlockNbr);						//块数量
 	log_i("Card BlockSize:      %d \r\n",SDCardInfo.BlockSize);					//块大小
	log_i("LogBlockNbr:         %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr));		//逻辑块数量
	log_i("LogBlockSize:        %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize));		//逻辑块大小
	log_i("Card Capacity:       %d MB\r\n",(uint32_t)(CardCap>>20));				//卡容量
#endif
#if 0		
    printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID);				//制造商ID	
 	printf("CardVersion:         %d \r\n",(uint32_t)(SDCardInfo.CardVersion));		//卡版本号
	printf("Class:               %d \r\n",(uint32_t)(SDCardInfo.Class));		    //
 	printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd);					//卡相对地址
	printf("Card BlockNbr:       %d \r\n",SDCardInfo.BlockNbr);						//块数量
 	printf("Card BlockSize:      %d \r\n",SDCardInfo.BlockSize);					//块大小
	printf("LogBlockNbr:         %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr));		//逻辑块数量
	printf("LogBlockSize:        %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize));		//逻辑块大小
	printf("Card Capacity:       %d MB\r\n",(uint32_t)(CardCap>>20));				//卡容量
#endif
}

int Init_FatFas_Mount(void)
{
    int retSD = f_mount(&fs, "0:", 0);
    return retSD;
}


/**
 * @brief  创建文件
 * @param [in] filename  "0:aa.txt"
 * 
 * @details  
 *          creat_file( "0:aa.txt" );
 */
int creat_file(char * filename)
{
    // f_mkfs( );
    int retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE); //打开文件，权限包括创建、写（如果没有该文件，会创建该文件）
    if(retSD==FR_OK) 
    {
        // printf("\r\ncreate  file success!!! \r\n");
        f_close(&fil); //关闭该文件
        return retSD;
    }
    else 
    {
        // printf("\r\ncreate  file error : %d\r\n",retSD);
        f_close(&fil); //关闭该文件
        return retSD;
    }
//    f_close(&fil); //关闭该文件
    // HAL_Delay(100);
}

int open_file(char * filename)
{
    // f_mkfs( );
    int retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE); //打开文件，权限包括创建、写（如果没有该文件，会创建该文件）
    if(retSD==FR_OK) 
    {
        return retSD;
    }
    else 
    {
        return retSD;
    }
    // HAL_Delay(100);
}

int close_file( )
{
    // f_mkfs( );
    f_close(&fil); //关闭该文件
}
/**
 * @brief open  write  close
 * @param [in] data 
 * @param [in] len 
 * 
 * @details 
 */
void write_file( char * data, uint32_t len )
{
    uint32_t byteswritten;
    /*##-3- Write data to the text files ###############################*/
    int retSD = f_write(&fil, data, len, (void *)&byteswritten);
    if(retSD)
        log_i(" write file error : %d\r\n",retSD);
    else
    {
        log_i(" write file sucess!!! \r\n");
        log_i(" write Data[%d] : %s\r\n",byteswritten,data);
    }
    /*##-4- Close the open text files ################################*/
    retSD = f_close(&fil);
    if(retSD)
        log_i(" close error : %d\r\n",retSD);
    else
        log_i(" close sucess!!! \r\n");
}

void SD_Read_block_Test(void)
{
    // uint8_t read_buf[512];	
    // int	sdcard_status = HAL_SD_ReadBlocks(&hsd, (uint8_t *)read_buf, 0, 1, 0xffff);
    // if(sdcard_status == HAL_OK)
    // { 
    //     printf("Read block data ok! \r\n");
    // }
    // else
    // {
    //     printf("Read block data fail! status = %d \r\n", sdcard_status);
    // }
}

/*

修改方案：

### SD 初始化
  ***创建文件失败错误***
  SDIO.c文件
      hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
      hsd.Init.ClockDiv = SDIO_INIT_CLK_DIV; //SDIO_TRANSFER_CLK_DIV;

### DMA

FIFO WORD


### 中断

SDIO  优于 DMA   优于  USB
值正好相反


###  heap  stack
0x1000
ox1500
 
 f_mount等要放任务中，增加了堆栈大小
  StartDefaultTask 堆栈要调大 1024


### 最大最小扇区大小

512 -> 4096
FATFS 两处地方
USB_Device 两处地方

###  USB 的调整

***CubeMX 自动将 MX_USB_DEVICE_Init() 函数放到 StartDefaultTask 中 ***

优于定义了 StartDefaultTask 虚函数， 不执行
需要手动移植到实际函数中

USB_Device初始化函数在默认任务中，所以要增加默认任务 StartDefaultTask 的堆栈，

  MX_USB_DEVICE_Init();

### 重写usbd_storage_if.c  
USB_DEVICE\App\usbd_storage_if.c
*** 不写的话 读取不到Upan信息， 显示upan大小都不对 ***

#define STORAGE_LUN_NBR                  1              // 逻辑单元号,只有一个外部flash,设置为1  
#define STORAGE_BLK_NBR                  2048           //扇区的数量,外部flash的大小是8Mbyte，有128块，每块16个扇区，故128*16=2048个扇区   
#define STORAGE_BLK_SIZ                  4096           // 每个扇区的大小,外部flash扇区的大小为4096byte/
以上通过输出SD信息改写

因为加入了FreeRTOS，fatfs对sd卡读写用的是发送消息机制，
所以usbd_storage_if.c里的读写不能再去调用bsp_driver_sd.c里的读写方法了，
大家有兴趣的可以对比一下有无FreeRTOS，bsp_driver_sd.c源码的内容

读写方法等
 
STM32F407 开发板没有用到 VUSB 电压检测，所以要在 usb_conf.h 里面 
将宏定义：#define VBUS_SENSING_ENABLED，屏蔽掉。
3，通过修改 usbd_conf.h 里面的 MSC_MEDIA_PACKET 定义值大小，可以一定程度提高
USB 读写速度（越大越快），本例程我们设置 12*1024，也就是 12K 大小。



***官方例程不支持大于 4G 的 SD 卡***
Middlewares\ST\STM32_USB_Device_Library\Class\MSC\Src
官方例程不支持大于 4G 的 SD 卡，得修改 usbd_msc_scsi.c 里面的 或 usbd_msc.h( Cubemx HAl)
SCSI_blk_addr 类型为 uint64_t，才可以支持大于 4G 的卡，官方默认是 uint32_t，最大只能支持 4G 卡。
注意：  usbd_msc.h
  uint64_t                 scsi_blk_addr;
  uint64_t                 scsi_blk_len;
usbd_msc_scsi.c 文件，是只读的，得先修改属性，去掉只读属性，才可以更改。


HS FS 标记
#define DEVICE_FS 		1
#define DEVICE_HS 		0

usb_devioce MSC_MEDIA_PAKCET 改32678   32*1024U

#### usb  编译
-DUSE_USB_OTG_FS

*/